希尔排序也是一种插入排序,核心思想:把需要排列的数字分割成多个子序列(在逻辑上划分)里面设计到一个缩小增量的概念dk,你就可以把它看作给数字上色,间隔dk的看作一组分好之后,各小组内再进行组内直接插入排序,划分的过程好比一堆标有数字的小球,我们给他们标上不同的颜色,颜色一样的就看为同一个小组但他们依然在各自的位置上,俗话说情人眼里出西施,你也可以理解为在每一轮循环中根据dk(缩小增量)把那几个划分到一起的视为你眼中的几个西施,此时在你的眼里高亮显示其他的不用管,你再按照这几个西施各自的数字大小进行排序,每次调整使得整体相对更有序一点,为最后一轮直接插入排序做准备即dk=1时。同时为啥i赋值是dk+1不是dk,因为我们这个代码0号位置不存数字,作为临时存储数字的区域,当然你可以自己换成int temp这种临时变量修改下代码就不需要加一,那这个代码教材案例一般给的是偶数个数字,奇数个怎么办,它同样可以用,只是第一轮划分有一个单独的数字分不到子序列里面,当dk逐渐缩小,它后面会被划进子序列中进行排序的不用担心,可以自己随便用几个数字顺着希尔排序代码过一下就容易懂,不算难。
具体代码如下:
#include<stdio.h>
// ShellSort函数实现
void ShellInsert(int a[], int length) {
int dk, i, j;
// 初始化增量dk,dk为数组长度的一半
// Shell排序的核心是对不同的增量进行插入排序
for (dk = length / 2; dk >= 1; dk = dk / 2) {
// 对每个增量dk进行插入排序
// 从dk位置开始处理,逐步向后推进到数组末尾
for (i = dk + 1; i <= length; i++) {
// 如果当前元素小于间隔dk位置的元素,则需要进行插入排序
if (a[i] < a[i - dk]) {
// 临时保存当前元素
a[0] = a[i];
// 将大于当前元素的值向后移动,为插入排序腾出位置
for (j = i - dk; j > 0 && a[0] < a[j]; j -= dk) {
a[j + dk] = a[j];
}
// 将当前元素插入到正确的位置,这里跟上面很像是因为上面循环j-=dk了我们需要重新移动到正确的位置
a[j + dk] = a[0];
}
}
}
}
int main() {
// 初始化数组,注意索引从1开始到10,0位置用于临时存储数据
int a[] = { 0, 49, 38, 65, 97, 76, 13, 27, 49, 55, 4 };
// 调用ShellInsert函数进行排序,数组长度为10
ShellInsert(a, 10);
// 打印排序后的数组
for (int i = 1; i <= 10; i++) {
printf("%d->", a[i]);
}
return 0;
}
运行结果: