1. 程式人生 > 實用技巧 >第8章學習小結

第8章學習小結

第8章學習了排序(主要是內部排序),可以分為插入排序、交換排序、選擇排序、歸併排序。內部排序的過程是一個逐步擴大記錄的有序序列長度的過程。

排序演算法效率的評價指標有兩個方面:執行時間和輔助空間

(1)執行時間:比較次數和移動次數都應該儘可能少

(2)輔助空間:理想的空間複雜度為O(1),即演算法執行期間所需要的輔助空間與待排序的資料量無關。

一、插入排序

直接插入排序(基於順序查詢)

課本P237頁 例8.1 手工實現直接插入排序

void InsertSort(SqList &L)
{//對順序表L做直接插入排序
    for(int i=2 ; i<L.length ; ++i) 
    {
        
if(L.r[i].key < L.r[i-1].key) //小於,需將r[i]插入有序子表 { L.r[0] = L.r[i] ; //將待插入的記錄暫存到監視哨中 L.r[i] = L.r[i-1] ; //r[i-1]後移 for(int j=i-2 ; L.r[0].key < L.r[j].key ; --j) //從後往前尋找插入位置 { L.r[j+1] = L.r[j] ; //
記錄逐個後移,直到找到插入位置 } L.r[j+1] = L.r[0] ; //將r[0]即原r[i],插入到正確位置 } }

(1)時間複雜度:O(n*n)

(2)空間複雜度:O(1)

(3)演算法特點:穩定排序,演算法簡便,更適合於除溼機路基本有序(非降序)的情況。

折半插入排序(基於折半查詢)

在插入第i個記錄時,需要經過log2n次比較,才能確定它應插入的位置

需要迴圈n-1次,每次先使用折半查詢法,查詢r[i]的插入位置,然後將r[i]插入表長為i-1的有序序列中,直到將r[n]插入表長為n-1的有序序列為止。

(1)時間複雜度:O(n*n)

(2)空間複雜度:O(1) (和直接插入排序相同,輔助空間只需要r[0])

(3)演算法特點:穩定排序,只能用於順序結構,適合初始記錄無序、n較大的情況。

希爾排序(縮小增量排序)

課本P240 例8.2 手工實現排序

希爾排序:第一趟取增量d1(d1<n)把全部記錄分成d1個組,所有間隔為d1的記錄分在同一組,在各個組中進行直接插入排序

第二趟取增量d2(d2<d1),重複上述的分組和排序

依次類推,直到所取的增量dt = 1,所有記錄在同一組中進行直接插入排序為止。

(1)時間複雜度:O(n3/2)

(2)空間複雜度:O(1)(和前面一樣,只需要一個輔助空間r[0])

二、交換排序

氣泡排序

課本P242 例8.3 手工實現排序

氣泡排序:在每一趟中,將每個記錄的關鍵字與下一個記錄相比較,如果L.r[i].key > L.r[i+1].key,則交換兩個記錄。依次類推,直到比較完第n-1個記錄和第n個記錄為止,這樣就完成了第一趟氣泡排序。此時關鍵字最大的記錄處於正確的位置(第n個)。

然後進行第二趟氣泡排序,對前n-1個記錄進行同樣的操作,結果是關鍵字次大的記錄處於第n-1個位置上。

重複這樣的操作,直到在某一趟排序過程中沒有進行過交換記錄的操作,說明序列已全部達到排序要求。

(1)時間複雜度:O(n*n)

(2)空間複雜度:O(1)(在交換時只需要一個輔助空間用來暫存記錄)

(3)演算法特點:穩定排序,當初始記錄無序、n較大時,不宜採用氣泡排序

快速排序

課本P244 例8.4 手工實現排序

快速排序採用 “分治法” 策略把一個序列分為較小和較大的兩個子序列,然後遞迴地排序兩個子序列。

快速排序:預處理:R(low).key,R(high).key 和 R((low+high)/2).key三者取中

挑選基準值:從數列中挑出一個元素,稱作 “基準”

分割:重新排序序列,所有比基準值小的元素擺放在基準前面,所有比基準值大的元素擺在基準後面(與基準值相等的數可以到任何一邊)。在這個分割結束之後,對基準值的排序就已經完成。

遞迴排序子序列:遞迴地將小於基準值元素的子序列和大於基準值元素的子序列排序。

(1)時間複雜度:O(nlog2n)

(2)空間複雜度:最好情況下 O(log2n),最壞情況下 O(n)

(3)演算法特點:不穩定排序,適合於順序結構,適用於初始記錄無序、n較大的情況

三、選擇排序

簡單選擇排序

課本P247 例8.5 手工實現排序

簡單選擇排序:第一趟從r[1]開始,通過n-1次比較,從n個記錄中選出關鍵字最小的記錄,記為r[k],交換r[1]和r[k]

第二趟從r[2]開始,通過n-2次比較,從n-1個記錄中選出關鍵字最小的記錄,記為r[k],交換r[2]和r[k]

依次類推...經過n-1趟,排序完成

void SelectSort(SqList &L)
{
    for(int i=1 ; i<L.length ; ++i)
    {
        k = i ;
        for(int j=i+1 ; j<=L.length ; ++j)
        {//選擇關鍵字最小的記錄
            if(L.r[j].key < L.r[k].key)
            {
                k = j ; //k指向此趟排序中關鍵字最小的記錄
             }
        }
         if(k != i)
         {//交換r[i]與r[k]
             t = L.r[i] ;
             L.r[i] = L.r[k] ;
             L.r[k] = t ;
          }
     }
}

(1)時間複雜度:O(n*n)

(2)空間複雜度:O(1)(同氣泡排序一樣,只有在交換兩個記錄時需要一個輔助空間)

(3)演算法特點:不穩定排序

堆排序

將序列看成是一個完全二叉樹,樹中所有非終端結點的值均不大於(不小於)其左、右孩子結點的值。

大根堆(小根堆):堆頂記錄的關鍵字最大(最小)(如果求非降序,需要建立大根堆)

課本P250、253

(1)時間複雜度:O(nlog2n)

(2)空間複雜度:O(1)(僅需要一個記錄大小供交換用的輔助儲存空間)

(3)演算法特點:不穩定排序

四、歸併排序

歸併排序

課本P254 例8.8 手工實現排序

歸併排序:設初始序列含有n個記錄,則可看成是n個有序的子序列,每個子序列的長度為1,然後兩兩歸併,得到 n/2 個長度為2或1的有序子序列;再兩兩歸併,重複操作,直到得到一個長度為n的有序序列為止。

(1)時間複雜度:O(nlog2n)

(2)空間複雜度:O(n)(用順序表實現歸併排序時,需要和待排序記錄個數相等的輔助儲存空間)

(3)演算法特點:穩定排序