算法熟记-排序系列-希尔排序
1. 简述
假设待排序数组为 int array[], 数组长度为n。
该方法实质上是一种分组插入方法。假设数组长度n=10,我们设定几个分组的个数为1,3,5。
首先,分5组,即(array[0],array[5]),
(array[1],array[6]),
(array[2],array[7]),
...,每组内部进行插入排序
然后,分3组,即(array[0],array[3],array[6],array[9]),
(array[1],array[4],array[7]),
(array[2],array[5],array[8]), 每组内部进行插入排序
最后,分1组,即array[0], array[1], ... , array[9], 进行插入排序
2. 复杂度
希尔排序是对普通插入排序的改进,之所以是改进,是因为,普通插入排序在插入的时候往往需要移动大量的数据,而分组,使得数组相对有序,移动的步长也有提示,不再是1了,因此会有效率上的提高,具体的证明不是很简单,也就不深究了。
由于是多次分组插入排序,是非稳定的排序。
O(n log n) 如果使用最佳的现在版本,但是具体怎么算出来的,确实不清楚。
3. 代码
有了前面插入排序的代码,这个代码理解起来就容易多了。
这里给出一个java中的代码,感觉代表性很强,也容易理解。
{
int i, j, k, temp, gap;
int[] gaps = { 1,5,13,43,113,297,815,1989,4711,11969,27901,84801,
213331,543749,1355339,3501671,8810089,21521774,
58548857,157840433,410151271,1131376761,2147483647 };
for (k=0; gaps[k]<n; k++) ;
while (--k >= 0) {
gap = gaps[k];
for (i=gap; i<n; i++){ // 因为是插入排序,当然是从第一组的第二个元素开始,即i=gap
temp = a[i];
j = i;
while (j>=gap && a[j-gap]>temp) {
a[j] = a[j-gap];
j = j-gap;
}
a[j] = temp;
}
}
}
关于分组方法,简单的可以使用3*i+1的方法产生,直到n/2,比如对于n=10,就是1,4。尽量要求分组个数之间没有公约数。也有一些经过证明的方法。
4. 参考资料
维基百科-希尔排序
http://en.wikipedia.org/wiki/Shell_sort
http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F