算法熟记-排序系列-希尔排序
2011-06-10 15:51
633 查看
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中的代码,感觉代表性很强,也容易理解。
void shellsort (int[] a, int n)
{
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 };
// 根据n计算,分组个数
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
假设待排序数组为 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中的代码,感觉代表性很强,也容易理解。
void shellsort (int[] a, int n)
{
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 };
// 根据n计算,分组个数
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
相关文章推荐
- 算法熟记-排序系列-归并排序
- 算法熟记-排序系列-基数排序
- 排序系列算法——希尔排序
- 算法熟记-排序系列-快速排序
- 算法系列-直接插入排序和希尔排序
- 算法系列(二)冒泡排序、选择排序、插入排序和希尔排序(Java实现)
- 算法熟记-排序系列-冒泡排序
- 算法熟记-排序系列-插入排序
- 算法熟记-排序系列-堆排序
- 算法熟记-排序系列-计数排序
- 算法熟记-排序系列-选择排序
- 白话经典算法系列之六 快速排序 快速搞定
- 算法-排序之希尔排序
- 白话经典算法系列之 快速排序 快速搞定
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- 白话经典算法系列之二 直接插入排序的三种实现
- (转) 白话经典算法系列之三 希尔排序的实现(附源代码实现)
- 白话经典算法系列之三 希尔排序的实现
- 白话经典算法系列之六 快速排序 快速搞定
- 【算法系列】排序算法(2)直接插入排序