希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
1.插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
2.但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位
假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:
13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10然后我们对每列进行排序:
10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45将上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:
10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45
排序之后变为:
最后以1步长进行排序(此时就是简单的插入排序了)。
步长串行
步长的选择是希尔排序的重要部分。只要最终步长为1任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。
步长串行 | 最坏情况下复杂度 |
---|---|
#include <stdio.h>
int main()
{
const int n = 9;
int i, j, temp;
int gap = 0; //步长
int a[] = {5, 87, 3, 2, 1,7,9,34,8};
while (gap<=n)
{
gap = gap * 3 + 1; //选择不大于需要排序元素个数的步长
}
while (gap > 0)
{
for ( i = gap; i < n; i++ )
{
j = i - gap;
temp = a[i];
while (( j >= 0 ) && ( a[j] > temp )) //纵向进行排序
{
a[j + gap] = a[j];
j = j - gap;
}
a[j + gap] = temp;
}
gap = ( gap - 1 ) / 3; //减少步长值到1,步长为1变为插入排序
}
for(i=0;i<9;i++)
{
printf("%3d",a[i]);
}
printf("\n");
}