希爾排序(改進的直接插入排序)
阿新 • • 發佈:2020-10-24
希爾排序是一種改進的直接插入排序。對於直接插入排序而言,當(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};
參考書籍:程傑 著,《大話資料結構》,清華大學出版社。