算法熟记-排序系列-希尔排序

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 (-->= 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

posted @ 2011-06-10 15:51  xiaodongrush  阅读(271)  评论(0编辑  收藏  举报