各類排序算法

1. 插入排序

 

 

插入排序的基本操作就是將一個數據插入到已經排好序的有序數據中 , 從而得到一個新的,個數加一的有序數據,算法適用於少量數據的排序, 時間複雜度爲 O(n^2) . 是穩定的排序方法。插入算法把要排序的數組分成兩部分:第一部分包含了這個數組的所有元素,但將最後一個元素除外,而第二部分就只包含這一個元素。在第一部分排序後,再把這個最後元素插入到此刻已是有序的第一部分裏的位置

 

算法步驟  

 

     1. 從有序數列和無序數列 {a2,a3, ,an} 開始進行排序;

 

   2. 處理第 i 個元素時 (i=2,3, ,n) , 數列 {a1,a2, ,ai-1} 是已有序的 , 而數列 {ai,ai+1, ,an} 是無序的。用 ai ai-1 a i-2, ,a1 進行比較 , 找出合適的位置將 ai 插入;

 

   3. 重複第二步,共進行 n-1 次插入處理,數列全部有序。

 

基本思想

 

     每次處理就是將無序數列的第一個元素與有序數列的元素從後往前逐個進行比較,找出插入位置,將該元素插入到有序數列的合適位置中。

 

 

注意事項

 

     在容器已經有序時將獲得最好的時間性能 (O(n)), 容器近似有序時也將獲得很好的時間性能

 

 

2. 樹排序  

 

 

  算法步驟      

 

       1. 首先執行查找算法,找出被插結點的父親結點。

 

   2. 判斷被插結點是其父親結點的左、右兒子。將被插結點作爲葉子結點插入。

 

   3. 若二叉樹爲空。則首先單獨生成根結點。

 

  注意:新插入的結點總是葉子結點。

 

  基本思想

 

      插入之後,直接構造成紅黑樹。第 i 項的插入最多需要 log2i 次迭代。如需要重構,則之多需要 (log2i)/2 次迭代

 

 

   注意事項

 

   1. 樹排序是快速而穩定的,但空間需求與 n 成線性關係

 

   2. 如果即將插入的一項 y 等於紅黑樹中已經存在的一項 x ,那麼 y 將被插入到 x 的右子樹中

 

 

 

3. 堆排序

 

 

 

  算法步驟   

 

      1. 初始化操作:將 R[1..n] 構造爲初始堆;

 

    2. 每一趟排序的基本操作:將當前無序區的堆頂記錄 R[1] 和該區間的最後一個記錄交換,然後將新的無序區調整爲堆 ( 亦稱重建堆 )  

 

  

  基本思想

 

    以大根堆爲例 ( 大根堆和小根堆:根結點 ( 亦稱爲堆頂 ) 的關鍵字是堆裏所有結點關鍵字中最小者的堆稱爲小根堆,又稱最小堆。

 

                         根結點 ( 亦稱爲堆頂 ) 的關鍵字是堆裏所有結點關鍵字中最大者,稱爲大根堆,又稱最大堆 )

 

        1. 先將初始文件 R[1..n] 建成一個大根堆 , 此堆爲初始的無序區

 

   2. 再將關鍵字最大的記錄 R[1]( 即堆頂 ) 和無序區的最後一個記錄 R[n] 交換,由此得到新的無序區 R[1..n-1] 和有序區 R[n] ,且滿足 R[1..n-1].keys R[n].key

 

   3. 由於交換後新的根 R[1] 可能違反堆性質,故應將當前無序區 R[1..n-1] 調整爲堆。然後再次將 R[1..n-1] 中關鍵字最大的記錄 R[1] 和該區間的最後一個記錄 R[n-1] 交換,由此得到新的無序區 R[1..n-2] 和有序區 R[n-1..n] ,且仍滿足關係 R[1..n- 2].keys R[n-1..n].keys ,同樣要將 R[1..n-2] 調整爲堆。

 

  ……

 

  直到無序區只有一個元素爲止。

 

 

 

   注意事項

 

      1. 只需做 n-1 趟排序,選出較大的 n-1 個關鍵字即可以使得文件遞增有序。

 

   2. 用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。堆排序和直接選擇相反:在任何時刻堆排序中無序區總是在有序區之前,且有序區是在原向量的尾部由後往前逐步擴大至整個向量爲止

 

      3. 堆排序的時間,主要由建立初始堆和反覆重建堆這兩部分的時間開銷構成,它們均是通過調用 Heapify 實現的。 堆排序的最壞時間複雜度爲 O(nlog2n) 。堆序的平均性能較接近於最壞性能。 由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的文件。

 

  堆排序是就地排序,輔助空間爲 O(1)

 

  它是不穩定 的排序方法。

 

 

    堆排序與直接選擇排序的區別

 

  直接選擇排序中,爲了從 R[1..n] 中選出關鍵字最小的記錄,必須進行 n-1 次比較,然後在 R[2..n] 中選出關鍵字最小的記錄,又需要做 n-2 次比較事實上,後面的 n-2   比較中,有許多比較可能在前面的 n-1 次比較中已經做過,但由於前一趟排序時未保留這些比較結果,所以後一趟排序時又重複執行了這些比較操作。

 

  堆排序可通過樹形結構保存部分比較結果,可減少比較次數。

 

 

4. 歸併排序

 

 

       算法步驟      

 

         1. 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列

 

   2. 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置

 

   3. 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置

 

   4. 重複步驟 3 直到某一指針達到序列尾

 

   5. 將另一序列剩下的所有元素直接複製到合併序列尾

 

 

    基本思想

 

        歸併排序是建立在歸併操作上的一種有效的排序 算法。該算法是採用分治法 Divide and Conquer )的一個非常典型的應用。

 

   將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表。

 

    注意事項

 

      1. 時間 O(nlogn)

 

     2. 空間 O(n)

 

   3. 與快速排序類似。

 

      4. 歸併排序是穩定的排序 . 即相等的元素的順序不會改變

 

 

5. 快速排序

 

 

      算法步驟

 

     1 設置兩個變量 I J ,排序開始的時候: I=0 J=N-1

 

   2 以第一個數組元素作爲關鍵數據,賦值給 key ,即 key=A[0]

 

   3 J 開始向前搜索,即由後開始向前搜索( J=J-1 ),找到第一個小於 key 的值 A[J] ,並與 A[I] 交換;

 

   4 I 開始向後搜索,即由前開始向後搜索( I=I+1 ),找到第一個大於 key A[I] ,與 A[J] 交換;

 

   5 重複第 3 4 5 步,直到 I=J (3,4 步是在程序中沒找到時候 j=j-1 i=i+1 ,直至找到爲止。找到並交換的時候 i j 指針位置不變。另外當 i=j 這過程一定正好是 i+ j+ 完成的最後另循環結束 )

 

 

基本思想

 

 

設要排序的數組是 A[0] …… A[N-1] ,首先任意選取一個數據(通常選用第一個數據,但從效率上講最好選樞軸, 樞軸指 first first+ (last-first)/2,last-1 中最小的那一項)作爲關鍵數據, 然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱爲一趟快速排序

 

  注意事項

 

 

1. 如果原來的數組時按照順序或者逆序排列的,則快速算法的效率是最高的。如果每次迭代中,樞軸是最小項或者最大項時,將出現最壞的情況。

 

2. 快速排序是不穩定的

 

3.worstSpace(n) n 成線性關係

 

4. 快速排序在平均情況下非常快,而在最壞情況下則很慢,它是不穩定的,並且也不是本地排序方法

 

5. 快速排序吸引人之處在於平均情況下的快速性

 

 

6. 冒泡法排序

 

 

算法步驟

 

 

基本思想

 

依次比較相鄰的兩個數,將小數放在前面,大數放在後面。即在第一趟:首先比較第 1 個和第 2 個數,將小數放前,大數放後。然後比較第 2 個數和第 3 個數,將小數放前,大數放後,如此繼續,直至比較最後兩個數,將小數放前,大數放後。至此第一趟結束,將最大的數放到了最後。在第二趟:仍從第一對數開始比較(因爲可能由於第 2 個數和第 3 個數的交換,使得第 1 個數不再小於第 2 個數),將小數放前,大數放後,一直比較到倒數第二個數(倒數第一的位置上已經是最大的),第二趟結束,在倒數第二的位置上得到一個新的最大數(其實在整個數列中是第二大的數)。如此下去,重複以上過程,直至最終完成排序。

 

 

注意事項

 

 

時間複雜度爲 O(n^2)

 

執行的總比較次數爲 n*(n-1)/2

 

 

 

7. 選擇法排序

 

 

 

算法步驟

 

基本思想

 

 

      1. 初始狀態:無序區爲 R[1..n] ,有序區爲空。

 

   2. 1 趟排序

 

  在無序區 R[1..n] 中選出關鍵字最小的記錄 R[k] ,將它與無序區的第 1 個記錄 R[1] 交換,

 

      使 R[1..1] R[2..n] 分別變爲記錄個數增加 1 個的新有序區和記錄個數減少 1    新無序區。 .....

 

   3. i 趟排序

 

  第 i 趟排序開始時,當前有序區和無序區分別爲 R[1..i-1] R(1 i n-1) 。該趟排序從當前無序區中選出關鍵字最小的記錄 R[k] ,將它與無序區的第 1 個記錄 R 交換,

 

      使 R [1..i] R 分別變爲記錄個數增加 1 個的新有序區和記錄個數減少 1 個的新無序區。

 

 

注意事項

 

 

1.n 個記錄的文件的直接選擇排序可經過 n-1 趟直接選擇排序得到有序結果

 

2. 時間複雜度爲 O(n^2)

 

3. 共執行比較的次數爲 n(n-1)/2

 

 

8. 基數排序

 

 

 

1. LSD 的基數排序適用於位數小的數列,如果位數多的話,使用 MSD 的效率會比較好,

 

MSD 的方式恰與 LSD 相反,是由高位數爲基底開始進行分配,其他的演算方式則都相同。

 

 

2. 時間效率:設待排序列爲 n 個記錄, d 個關鍵碼,關鍵碼的取值範圍爲 radix ,則進行鏈式基數排序的時間複雜度爲 O(d(n+radix)) ,其中,一趟分配時間複雜度爲 O(n)

 

    一趟收集時間複雜度爲 O(n) ,共進行 d 趟分配和收集。

 

    空間效率:需要 2*radix 個指向隊列的輔助空間,以及用於靜態鏈表的 n 個指針

 

 

3. 在某些時候,基數排序法的效率高於其它的比較性排序法。

 

 

算法步驟

 

 

首先根據個位數的數值,在走訪數值時將它們分配至編號 0 9 的桶子中:

 

      0

 

   1 81

 

   2 22

 

   3 73 93 43

 

   4 14

 

   5 55 65

 

   6

 

   7

 

   8 28

 

   9 39

 

     接下來將這些桶子中的數值重新串接起來,成爲以下的數列:

 

   81, 22, 73, 93, 43, 14, 55, 65, 28, 39

 

  接着再進行一次分配,這次是根據十位數來分配:

 

   0

 

   1 14

 

   2 22 28

 

   3 39

 

   4 43

 

   5 55

 

   6 65

 

   7 73

 

   8 81

 

   9 93

 

  接下來將這些桶子中的數值重新串接起來,成爲以下的數列:

 

   14, 22, 28, 39, 43, 55, 65, 73, 81, 93

 

      這時候整個數列已經排序完畢;如果排序的對象有三位數以上,則持續進行以上的動作直至最高位數爲止。

 

 

基本思想

 

 

基數排序的方式可以採用 LSD Least significant digital )或 MSD Most significant digital ), LSD 的排序方式由鍵值的最右邊開始,而 MSD 則相反,由鍵值的最左邊開始。

 

 

注意事項

 

 

73, 22, 93, 43, 55, 14, 28, 65, 39, 81

 

 

每一趟從待排序的數據元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最後,直到全部待排序的數據元素排完。

 

  選擇排序是不穩定的排序方法。

 

設想被排序的數組 R 1..N ]垂直豎立,將每個數據元素看作有重量的氣泡,根據輕氣泡不能在重氣泡之下的原則,從下往上掃描數組 R ,凡掃描到違反本原則的輕氣泡,就使其向上 " 漂浮 " ,如此反覆進行,直至最後任何兩個氣泡都是輕者在上,重者在下爲止

 

 

 

發佈了56 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章