1. 程式人生 > 實用技巧 >希爾排序(改進的直接插入排序)

希爾排序(改進的直接插入排序)

  希爾排序是一種改進的直接插入排序。對於直接插入排序而言,當(1)記錄個數較少;(2)記錄本身基本有序時,其效率很高。所以我們從這兩個方面來對直接插入排序進行改進,(1)將記錄進行分組成幾個子序列,在子序列中進行直接插入排序;(2)當整個序列基本有序時,對全體記錄進行直接插入排序。

  為實現基本有序,我麼採用跳躍式分割的策略,將相距為某個增量的記錄組成一個子序列。

  希爾排序的基本思想:將具有大量記錄的順序表進行分組成若干子序列,對子序列進行直接插入排序,當整個序列基本有序時,再對全體記錄進行一次直接插入排序。

  以順序表L = {0,9,1,5,8,3}為例,length = 5,參與排序的紀錄為r[1]~r[5],r[0]充當哨兵(中間變數),協助排序的進行。程式碼如下所示:

 1 //希爾排序,改進的直接插入排序
 2 //當(1)記錄個數較少時(2)記錄本身基本有序。
 3 //直接插入排序的效率很高
 4 //希爾排序通過以下方式構造這兩個條件
 5 //(1)將原本大量的記錄進行分組,對子序列進行直接插入排序;(2)整個序列基本有序後,在進行一次直接插入排序。
 6 //對記錄進行分組,採用跳躍式分割策略,將相距某個增量的記錄組成一個子序列,而不能平均分割。
 7 void ShellSort(SqList* L)
 8 {
 9     int i, j;
10     int increment = L->length;//初始增量
11 
12     do
13     {
14 //兩個記錄組成一個子序列 15 //增量序列的最後一個增量值必須為1 16 increment = increment / 3 + 1;//增量序列 17 18 //當increment=1時,對全體記錄進行直接插入排序 19 //當increment!=1時,對子序列進行直接插入排序 20 //i = increment + 1,假設r[i - increment]已經放好了位置 21 for (i = increment + 1; i <= L->length; i++) 22 {
23 if (L->r[i] < L->r[i - increment])//後面的小於前面的,則需要進行插入 24 { 25 L->r[0] = L->r[i];//哨兵 26 27 //與直接插入排序不同的是,這裡需要判斷j > 0 28 for (j = i - increment; j > 0 && L->r[0] < L->r[j]; j -= increment) 29 L->r[j + increment] = L->r[j];//記錄後移,查詢插入位置 30 31 L->r[j + increment] = L->r[0];//插入到正確位置 32 } 33 } 34 } while (increment > 1); 35 }

  順序表中的記錄變化如下:

  注意,以下子序列中的第一個記錄為哨兵,不參與排序,只是協助排序的進行。

  在increment=2中:

    Step1中,將5通過簡單選擇排序插入{9}中,結果為{5,9};

    Step2中,將8插入{1}中,結果為{1,8};

    Step3中,將3插入{5,9}中,結果為{3,5,9};

  在increment=1中,對整個序列進行簡單選擇排序:

    Step1中,將1插入{3}中,結果為{1,3};

    Step2中,將5插入{1,3}中,結果為{1,3,5};

    Step3中,將8插入{1,3,5}中,結果為{1,3,5,8};

    Step4中,將9插入{1,3,5,8}中,結果為{1,3,5,8,9};

參考書籍:程傑 著,《大話資料結構》,清華大學出版社。