希尔排序实质上是一种分组插入方法。它的基本思想是:对于n个待排序的数列,取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。然后减小gap的值,并重复执行上述的分组和排序。重复这样的操作,当gap=1时,整个数列就是有序的。
详细例子见下图:
图中10个元素,gap = 5,则对应下标的元素组成一个组:
下标为0和5组成一个组,即(1,0);
下标为1和6组成一个组,即(3,4);
下标为2和7组成一个组,即(8,6);
下标为3和8组成一个组,即(9,5);
下标为4和9组成一个组,即(2,7);
然后对在每个组内进行直接插入排序,则排序后的结果为:
下标为0和5组成一个组,即(0,1);
下标为1和6组成一个组,即(3,4);
下标为2和7组成一个组,即(6,8);
下标为3和8组成一个组,即(5,9);
下标为4和9组成一个组,即(2,7);
则排序后的整个序列为:
gap = 2,将上面序列分为2个组,则分成的组为:
下标0,2,4,6,8的元素组成一个组,即元素(0,6,2,4,9)组成一个组;
下标1,3,5,7,9的元素组成一个组,即元素(3,5,1,8,7)组成一个组;
然后对在每个组内进行直接插入排序,则排序后的结果为:
下标0,2,4,6,8的元素组成一个组,即元素(0,2,4,6,9)组成一个组;
下标1,3,5,7,9的元素组成一个组,即元素(1,3,5,7,8)组成一个组;
排序后整个序列为:
gap = 1,将上面的表组成一个表,对其进行插入排序操作,结果为:
具体代码实现如下图所示:
#include<stdio.h>
void ShellSort(int arr[], int len)
{
for (int gap = len / 2; gap > 0; gap /= 2) //gap为步长,每次减为原来一半
{
for (int i = 0; i < gap; i++) //gap个组,对每个组进行插入排序操作
{
//每组的第一个元素为有序序列,从每组的第二个元素与第一个元素进行比较插入适当位置,
//其中每组的第一个元素对应的下标为i,第二个元素对应的下标为i + gap
for (int j = i + gap; j < len; j += gap) //遍历无序序列中的元素
{
for (int k = i; k < j; k += gap) //遍历有序序列中的元素一一与无序序列中的某个元素进行比较,执行插入操作
{
if (arr[k] > arr[j])
{
int temp = arr[j]; // 保存无序序列中的元素
for (int m = j; m > k; m -= gap) //将有序序列中从大于无序序列的第一个元素开始,所有的元素后移一位
arr[m] = arr[m - gap];
arr[k] = temp;
}
}
}
}
}
}
int main()
{
int arrList[] = { 1, 3, 8, 9, 2, 0, 4, 6, 5, 7 };
int length = (int)sizeof(arrList) / sizeof(arrList[0]);
printf("排序前: ");
for (int i = 0; i < length; i++)
printf("%d ", arrList[i]);
printf("\n");
ShellSort(arrList, length);
printf("排序后: ");
for (int i = 0; i < length; i++)
printf("%d ", arrList[i]);
printf("\n");
return 0;
}
编译后结果如下图所示: