这是我参与18月更文挑战的第22天,活动详情查看:2021最后一次更文挑战
希尔排序(shell排序)
思想:希尔排序又可以称为缩小增量排序(它本质也是插入排序)接下来就来看下他的思路
假设关键字为 49,38,65,97,76,13,27,49,55,04 我们采用希尔排序
每排序一次 增量就减少一次 直到减少为1就结束排序,增量d是怎么选择呢?
一般选择增量d1 = n/2 d2=d1/2 ... 所以在这一次的排序中 我们的增量有 5,2,1
-
1.增量为5 我们就进行分组 (49,13),(38,27),(65,49),(97,55),(76,04)在每个组中进行排序 排序后的结果为13,27,49,55,04,49,38,65,97,76
-
2.增量为2 我们进行第二次排序分组 (13,49,04,38,97),(27,55,49,65,76) 我们在这两个组中进行插入排序 排序后的结果为 04,27,13,49,38,55,49,65,97,76
-
3.增量1 我们进行第三次排序分组 则直接04,27,13,49,38,55,49,65,97,76进行排序 排序结果为 04 13 27 38 49 49 55 65 76 97
在上面的三次过程中 其实就是根据增量来堆排序数列进行分组 在每个分组进行直接插入排序 而在增量为1的时候 实际上就是一次插入排序 因为直接插入排序 若待排序数越有序查询越高 而我们经过希尔排序 一次次缩小增量 则排序的数就越趋近于有序
在理解了上面的过程来看希尔排序的代码就很好理解了(关键是分组哪里要选好)
直接插入排序
void inserSort(int a[],int n){
int i,j;
for(i=2;i<=n;i++){ //从第二个位置插入到前面已经拍好的位置中
if(a[i]<a[i-1]) { //若a[i]小于前面的值
a[0] = a[i]; //a[0]做哨兵
for(j=i-1;a[0]<a[j];--j){ //从后面往前查需要蒋这个数据插入到哪一个位置
a[j+1]=a[j]; //找到插入位置往后移动
}
a[j+1]=a[0];//插入数据
}
}
}
希尔排序
void ShellSort(int a[],int n){
//a[0]作为暂存单元 dk就是增量 有几次增量就要循环几次排序 而在增量内部的排序和直接插入排序相似
for(int dk=n/2;dk>=1;dk=dk/2){
for(i=dk+1;i<=n;i++){
if(a[i]<a[i-dk]){
a[0] = a[i];
for(j=j-dk;j>0&&a[0]<a[j]; j-=dk){
a[j+dk] = a[j];
}
a[j+dk]=a[0];
}
}
}
}
总结:
其中第一层for循环时要进行几次分组排序
第二层第三层的for循环实际上就是直接插入排序 可以参考上面直接插入排序的算法
这也就说明希尔排序实际上是更高效的直接插入排序!