简介
希尔排序是插入排序的优化版本,又名缩小增量排序。
基本思想是把数组按一步长(gap)分组,后对每一组进行插入排序,通过缩小步长使每一组的数据增加,当步长为1时,完成对整组数据的排序。
例如现在有一个数组:
6 3 1 9 4 8 2 5 7 0
以步长5来进行排序,将6和8,3和2,1和5。。。。进行排序,
6 2 1 7 0 8 3 5 9 4
在以步长2(5/2)来排序,将{6,1,0,3,9}和{2,7,8,5,4}进行排序,
0 2 1 4 3 5 6 7 9 8
最后以步长1(2/2)来完成排序
0 1 2 3 4 5 6 7 8 9
由于直接插入排序在元素基本有序的情况下效率是很高的,希尔排序通过缩小数组增量的手段来使直接插入排序的效率发挥到最大。
代码
void ShellSort(int a[], int n)
{
int gap,i,j,m,temp;
for(gap = n/2; gap >= 1; gap /= 2)//缩小步长
for(i = 0; i < gap; i++)//对各组进行排序
for(j = i + gap; j < n; j += gap)//插入排序
if (a[j] < a[j - gap])
{
temp = a[j];
for (m = j - gap; m >= 0 && a[m] > temp; m -= gap)
a[m + gap] = a[m];
a[m + gap] = temp;
}
}
其实我们可以不用固执的一组一组的进行插入排序,在i循环遍历到的每一个数进行其组内的插入排序,比如先进行a1在a组内的插入,再执行b1在b组内的插入,再去执行a2在a组内的插入。。。。。(步长为2的情况)。
void ShellSort(int a[], int n)
{
int gap,i,j,temp;
for(gap = n/2; gap >= 1; gap /= 2)//缩小步长
for(i = gap; i < n; i++)//对遍历到的数进行插入排序
if (a[i] < a[i - gap])
{
temp = a[i];
for (j = i - gap; j >= 0 && a[j] > temp; j -= gap)
a[j + gap] = a[j];
a[j + gap] = temp;
}
}
对于步长增量并不一定要使用gap/2的方式,只要满足一下两个要求就可以了
1. 最后一个增量必须为1
2. 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
事实上增量的选择也会影响到希尔排序的复杂度,例如希尔增量(
n/2i
)时间复杂度为O(n²),而Hibbard增量(
2k−1
)的希尔排序的时间复杂度为
O(n3/2)
.