比較排序和非比較排序
常見的排序演算法都是比較排序,非比較排序包括計數排序、桶排序和基數排序,非比較排序對資料有要求,因為資料本身包含了定位特徵,所有才能不通過比較來確定元素的位置。
比較排序的時間複雜度通常為o(n2)或者o(nlogn),比較排序的時間複雜度下界就是o(nlogn),而非比較排序的時間複雜度可以達到o(n),但是都需要額外的空間開銷。
比較排序時間複雜度為o(nlogn)的證明:
a1,a2,a3……an序列的所有排序有n!種,所以滿足要求的排序a1』,a2』,a3』……an』(其中a1』<=a2』<=a3』……<=an』)的概率為1/n!。基於輸入元素的比較排序,每一次比較的返回不是0就是1,這恰好可以作為決策樹的乙個決策將乙個事件分成兩個分支。比如氣泡排序時通過比較a1和a2兩個數的大小可以把序列分成a1,a2……an與a2,a1……an(氣泡a2上公升乙個身位)兩種不同的結果,因此比較排序也可以構造決策樹。根節點代表原始序列a1,a2,a3……an,所有葉子節點都是這個序列的重排(共有n!個,其中有乙個就是我們排序的結果a1』,a2』,a3』……an』)。如果每次比較的結果都是等概率的話(恰好劃分為概率空間相等的兩個事件),那麼二叉樹就是高度平衡的,深度至少是log(n!)。
又因為
n! < nn ,兩邊取對數就得到log(n!)n!=n(n-1)(n-2)(n-3)…1 > (n/2)^(n/2) 兩邊取對數得到 log(n!) > (n/2)log(n/2) = ω(nlogn),所以 log(n!) = ω(nlogn)。
因此log(n!)的增長速度與 nlogn 相同,即 log(n!)=θ(nlogn),這就是通用排序演算法的最低時間複雜度o(nlogn)的依據。
穩定排序和非穩定排序
簡單地說就是所有相等的數經過某種排序方法後,仍能保持它們在排序之前的相對次序,我們就
說這種排序方法是穩定的。反之,就是非穩定的。
比如:一組數排序前是a1,a2,a3,a4,a5,其中a2=a4,經過某種排序後為a1,a2,a4,a3,a5,
則我們說這種排序是穩定的,因為a2排序前在a4的前面,排序後它還是在a4的前面。假如變成a1,a4,
a2,a3,a5就不是穩定的了。
內排序和外排序
在排序過程中,所有需要排序的數都在記憶體,並在記憶體中調整它們的儲存順序,稱為內排序;
在排序過程中,只有部分數被調入記憶體,並借助記憶體調整數在外存中的存放順序排序方法稱為外排序。
平均情況
最好情況
最壞情況
歸併排序
o(nlogn)
o(nlogn)
o(nlogn)
基數排序
o(n)
o(n)
o(n)
快速排序
o(nlogn)
o(nlogn)
o(n2)
希爾排序
o(n1.5)
o(n)
o(n1.5)
插入排序
o(n2)
o(n)
o(n2)
選擇排序
o(n2)
o(n2)
o(n2)
排序的穩定性和複雜度
不穩定:
穩定:
**參考
#_*_coding:utf-8_*_
import random
#選擇排序遞迴實現
defsel_sort_rec
(list
,n):
if n ==0:
return
max_j = n
for j in
range
(n):
iflist
[j]>
list
[max_j]
: max_j = j
list
[n],
list
[max_j]
=list
[max_j]
,list
[n] sel_sort_rec(
list
,n-1
)#選擇排序迴圈實現
defsel_sort
(list):
for i in
range
(len
(list))
: min_j = i
for j in
range
(i+1
,len
(list))
:iflist
[min_j]
>
list
[j]:
min_j = j
list
[min_j]
,list
[j]=
list
[min_j]
,list
[j]#插入排序遞迴實現
defins_sort_rec
(list
,n):
if n ==0:
return
ins_sort_rec(
list
,n-1
) j = n
while j >
0and
list
[j-1
]>
list
[j]:
list
[j-1],
list
[j]=
list
[j],
list
[j-1
] j -=
1#插入排序迴圈實現
defins_sort
(list):
for i in
range(1
,len
(list))
: j = i
while j >
0and
list
[j-1
]>
list
[j]:
list
[j-1],
list
[j]=
list
[j],
list
[j-1
] j -=
1#遞迴的合併排序實現
defmerge_sort
(a):
iflen
(a)<=1:
return a
middle =
len(a)//2
lefta = a[
:middle]
righta = a[middle:
] lefta_sorted = merge_sort(lefta)
righta_sorted = merge_sort(righta)
return merge(lefta_sorted,righta_sorted)
#合併兩個已經排序的序列
defmerge
(left, right)
: i, j =0,
0 alist =
while i <
len(left)
and j <
len(right)
:if left[i]
< right[j]:)
i +=
1else:)
j +=
1while i <
len(left)
:#左邊剩餘資料處理
) i +=
1while j <
len(right)
:#右邊剩餘資料處理
) j +=
1return alist
defmain()
:list
=[random.randint(1,
10)for x in
range(10
)]sel_sort_rec(
list,9
)print
("選擇排序遞迴實現:"
+str
(list))
sel_sort(
list
)print
("選擇排序迴圈實現:"
+str
(list))
merge_sort(
list
)print
("合併排序實現結果:"
+str
(list))
if __name__ ==
'__main__'
: main(
)
參考鏈結 排序演算法比較
本章中已經研究並仔細分析了多個內部排序方法。對於這些內部排序方法之間的比較,主要從以下幾個方面綜合考慮 時間複雜度 空間複雜度 演算法穩定性 演算法簡單性 待排序記錄數 n的大小 記錄本身的資訊量等。選擇n 個整數組成一些隨機排序,各種內部排序方法的實際時間如圖 7 10 所示。從時間複雜度看,所有...
排序演算法比較
排序方法 最好時間 平均時間 最壞時間 輔助儲存 穩定性備註 簡單選擇排序 o n2 o n2 o n2 o 1 不穩定n小時較好 直接插入排序 o n o n2 o n2 o 1 穩定大部分已有序時較好 氣泡排序 o n o n2 o n2 o 1 穩定n小時較好 希爾排序 o n o nlogn...
比較排序演算法
常用的比較排序演算法有 直接插入排序,希爾排序,選擇排序,堆排序,氣泡排序,快速排序,歸併排序等。它們的時間複雜度及空間複雜度為 實現 如下 includeusing namespace std include include 插入排序 void insertsort int a,size t si...