常用的內部排序方法有:交換排序(冒泡排序、快速排序)、選擇排序(簡單選擇排序、堆排序)、插入排序(直接插入排序、希爾排序)、歸並排序、基數排序(一關鍵字、多關鍵字)。
一、冒泡排序:
1.基本思想:
兩兩比較待排序數據元素的大小,發現兩個數據元素的次序相反時即進行交換,直到沒有反序的數據元素為止。
2.排序過程:
設想被排序的數組R[1..N]垂直豎立,將每個數據元素看作有重量的氣泡,根據輕氣泡不能在重氣泡之下的原則,從下往上掃描數組R,凡掃描到違反本原則的輕氣泡,就使其向上"漂浮",如此反復進行,直至最后任何兩個氣泡都是輕者在上,重者在下為止。
【示例】:
49 13 13 13 13 13 13 13
38 49 27 27 27 27 27 27
65 38 49 38 38 38 38 38
97 65 38 49 49 49 49 49
76 97 65 49 49 49 49 49
13 76 97 65 65 65 65 65
27 27 76 97 76 76 76 76
49 49 49 76 97 97 97 97
二、快速排序(Quick Sort)
1.基本思想:
在 當前無序區R[1..H]中任取一個數據元素作為比較的"基准"(不妨記為X),用此基准將當前無序區划分為左右兩個較小的無序區:R[1..I-1]和 R[I+1..H],且左邊的無序子區中數據元素均小於等於基准元素,右邊的無序子區中數據元素均大於等於基准元素,而基准X則位於最終排序的位置上,即 R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),當R[1..I-1]和R[I+1..H]均非空時,分別對它們進行上述的划分過 程,直至所有無序子區中的數據元素均已排序為止。
2.排序過程:
【示例】:
初始關鍵字 [49 38 65 97 76 13 27 49]
第一次交換后 [27 38 65 97 76 13 49 49]
第二次交換后 [27 38 49 97 76 13 65 49]
J向左掃描,位置不變,第三次交換后 [27 38 13 97 76 49 65 49]
I向右掃描,位置不變,第四次交換后 [27 38 13 49 76 97 65 49]
J向左掃描 [27 38 13 49 76 97 65 49]
(一次划分過程)
初始關鍵字 [49 38 65 97 76 13 27 49]
一趟排序之后 [27 38 13] 49 [76 97 65 49]
二趟排序之后 [13] 27 [38] 49 [49 65]76 [97]
三趟排序之后 13 27 38 49 49 [65]76 97
最后的排序結果 13 27 38 49 49 65 76 97
三、簡單選擇排序
1.基本思想:
每一趟從待排序的數據元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最后,直到全部待排序的數據元素排完。
2.排序過程:
【示例】:
初始關鍵字 [49 38 65 97 76 13 27 49]
第一趟排序后 13 [38 65 97 76 49 27 49]
第二趟排序后 13 27 [65 97 76 49 38 49]
第三趟排序后 13 27 38 [97 76 49 65 49]
第四趟排序后 13 27 38 49 [49 97 65 76]
第五趟排序后 13 27 38 49 49 [97 97 76]
第六趟排序后 13 27 38 49 49 76 [76 97]
第七趟排序后 13 27 38 49 49 76 76 [ 97]
最后排序結果 13 27 38 49 49 76 76 97
四、堆排序(Heap Sort)
1.基本思想:
堆排序是一樹形選擇排序,在排序過程中,將R[1..N]看成是一顆完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關系來選擇最小的元素。
2.堆的定義: N個元素的序列K1,K2,K3,...,Kn.稱為堆,當且僅當該序列滿足特性:
Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])
堆實質上是滿足如下性質的完全二叉樹:樹中任一非葉子結點的關鍵字均大於等於其孩子結點的關鍵字。例如序列10,15,56,25,30,70就是一個 堆,它對應的完全二叉樹如上圖所示。這種堆中根結點(稱為堆頂)的關鍵字最小,我們把它稱為小根堆。反之,若完全二叉樹中任一非葉子結點的關鍵字均大於等 於其孩子的關鍵字,則稱之為大根堆。
3.排序過程:
堆排序正是利用小根堆(或大根堆)來選取當前無序區中關鍵字小(或最大)的記錄實現排序的。我們不妨利用大根堆來排序。每一趟排序的基本操作是:將當前無 序區調整為一個大根堆,選取關鍵字最大的堆頂記錄,將它和無序區中的最后一個記錄交換。這樣,正好和直接選擇排序相反,有序區是在原記錄區的尾部形成並逐 步向前擴大到整個記錄區。
【示例】:對關鍵字序列42,13,91,23,24,16,05,88建堆
五、直接插入排序(Insertion Sort)
1. 基本思想:
每次將一個待排序的數據元素,插入到前面已經排好序的數列中的適當位置,使數列依然有序;直到待排序數據元素全部插入完為止。
2. 排序過程:
【示例】:
[初始關鍵字] [49] 38 65 97 76 13 27 49
J=2(38) [38 49] 65 97 76 13 27 49
J=3(65) [38 49 65] 97 76 13 27 49
J=4(97) [38 49 65 97] 76 13 27 49
J=5(76) [38 49 65 76 97] 13 27 49
J=6(13) [13 38 49 65 76 97] 27 49
J=7(27) [13 27 38 49 65 76 97] 49
J=8(49) [13 27 38 49 49 65 76 97]
六、希爾排序
1.排序思想:
先 取一個小於n的證書d1作為第一個增量,把文件的全部記錄分成d1組。所有距離為d1的倍數的記錄放在同一組中。先在各組內進行直接插入排序,然后取第二 個增量d2<d1重復上述的分組和排序,直到所取的增量dt=1,即所有記錄放在同一組中進行直接插入排序為止。該方法實際上是一種分組插入方法。
2.排序過程:
[初始關鍵字] 72 28 51 17 96 62 87 33 45 24
d1=n/2=5 62 28 33 17 24 72 87 51 45 96
d2=d1/2=3 17 24 33 62 28 45 87 51 72 96
d3=d2/2=1 17 24 28 33 45 51 62 72 87 96
七、歸並排序
1.排序思想:
設兩個有序的子文件(相當於輸入堆)放在同一向量中相鄰的位置上:R[low..m],R[m+1..high],先將它們合並到一個局部的暫存向量R1(相當於輸出堆)中,待合並完成后將R1復制回R[low..high]中。
2.排序過程:
【示例】:
初始關鍵字 [46][38][56][30][88][80][38]
第一趟歸並后[38 46][30 56][80 88][38]
第二趟歸並后[30 38 46 56][38 80 88]
最終歸並結果[30 38 38 46 56 80 88]
八、基數排序
1.排序思想:
(1)根據數據項個位上的值,把所有的數據項分為10組;
(2)然后對這10組數據重新排列:把所有以0結尾的數據排在最前面,然后是結尾是1的數據項,照此順序直到以9結尾的數據,這個步驟稱為第一趟子排序;
(3)在第二趟子排序中,再次把所有的數據項分為10組,但是這一次是根據數據項十位上的值來分組的。這次分組不能改變先前的排序順序。也就是說,第二趟排序之后,從每一組數據項的內部來看,數據項的順序保持不變;
(4)然后再把10組數據項重新合並,排在最前面的是十位上為0的數據項,然后是10位為1的數據項,如此排序直到十位上為9的數據項。
(5)對剩余位重復這個過程,如果某些數據項的位數少於其他數據項,那么認為它們的高位為0。
2.排序過程
【示例】
初始關鍵字 421 240 035 532 305 430 124
第一趟排序后[240 430] [421] [532] [124] [035 305]
第二趟排序后(305) (421 124) (430 532 035) (240)
最后排序結果(035) (124) (240) (305) (421 430) (532)
時間復雜度
排序方法 最好情況 最壞情況 平均情況 穩定性 空間復雜度
冒泡排序 O(n) O(n2) O(n2) 穩定
快速排序 O(nlogn) O(n2) O(nlogn) 不穩定
簡單選擇排序 O(n2) 不穩定
堆排序 O(nlogn) 不穩定
直接插入排序 O(n) O(n2) O(n2) 穩定
希爾排序 O(n1.3) 不穩定
歸並排序 O(nlogn) O(nlogn) O(nlogn) 穩定
基數排序 O(d(r+n)) 穩定
(1)選擇排序最好是 O(n2)
(2)快速排序在平均情況下復雜性為O(nlogn),最壞情況 O(n2),最好O(nlogn)
(3)堆排序和合並排序在最壞情況下復雜性為O(nlogn)。可見,合並排序和堆排序是比較排序算法中時間復雜度最優算法。
空間復雜度
空間性能是排序所需輔助空間大小
所有簡單排序和堆排序都是0(1)
快速排序為0(logn),要為遞歸程序執行過程棧所需的輔助空間
歸並排序和基數排序所需輔助空間最多,為O(n)