希尔排序(改进的直接插入排序)
希尔排序是一种改进的直接插入排序。对于直接插入排序而言,当(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};
相关链接:
冒泡排序 https://www.cnblogs.com/yongjin-hou/p/13858510.html
简单选择排序 https://www.cnblogs.com/yongjin-hou/p/13859148.html
直接插入排序 https://www.cnblogs.com/yongjin-hou/p/13861458.html
堆排序 https://www.cnblogs.com/yongjin-hou/p/13873770.html
归并排序 https://www.cnblogs.com/yongjin-hou/p/13921147.html
快速排序 https://www.cnblogs.com/yongjin-hou/p/13950379.html
参考书籍:程杰 著,《大话数据结构》,清华大学出版社。