希尔排序是对直接排序插入排序算法的改进,又称为缩小增量排序。其基本思想是将待排序的记录分成几组,每组中元素都比原来的序列少,从而减少参与直接插入排序的数据量,在各组中分别进行直接插入排序。经过几次分组排序后,记录的排列已经基本有序,这个时候在对所有的记录实施直接排序。

  具体步骤描述如下:假设待排序的记录为n个,先取整数 d< n,例如 d= [n/2](取整,不大于n/2的最大整数),将所有距离为d的记录构成一组,从而将真个待排序序列分割成d个子序列,对每个分组分别进行直接插入排序,然后再缩小间隔d,例如 d = d/2,重复上述的分组,在对每个分组分别进行直接插入排序,直到最后取 d = 1,即将所有的记录都放在一组进行一次直接插入排序,最终将所有的记录重新排泄成按关键字有序的序列。

  (注:d 的取值不一定是 n/2,每次缩小间隔 d 也不一定是 d/2,只要逐渐缩小,最后到d = 1,即可)

  这里举个实例分析:

    初始状态: 125 11 22 34 15 44 76 66 100 8 14 20 2 5 1        共15个元素

    第一次分组:125 11 22 34 15 44 76 66 100 8 14 20 2 5 1      取d=[15/2] = 7,分成7组,相同分组内的元素用相同颜色表示

     组内排序:1 11 8 14 15 2 5 66 100 22 34 20 44 76 125  在同一个组内使用直接插入排序算法,使每个小组内是有序的

    第二次分组:1 11 8 14 15 2 5 66 100 22 34 20 44 76 125  去d =[7/2] = 3,分成3组,相同分组内的元素用相同的颜色表示

     组内排序:1 11 2 5 15 8 14 34 20 22 66 100 44 76 125  在同一个组内使用直接插入排序算法,使每个小组内是有序的

    第三次分组:1 11 2 5 15 8 14 34 20 22 66 100 44 76 125  去d =[3/2] = 1,分成1组,所有元素在同一个组,现在的序列基本有序,使用直接插入排序比较快

     组内排序:1 2 5 8 11 14 15 20 22 34 44 66 76 100 125  在同一个组内使用直接插入排序算法,使每个小组内是有序的

  

 

  参考代码:

 

#include <stdio.h>

#define MAX_NUM 80

void shellsort(int* a, int n)
{
    for(int d = n/2; d >= 1; d = d/2)
    {
        int guard = -1;
        for (int i = 0; i < n; i++)
        {
            guard = a[i];
            int j = i - d;
            while(guard < a[j] && j >= 0)
            {
                a[j+d] = a[j];
                j = j-d;
            }
            a[j+d] = guard;
        }
        
        for(int i = 0; i < n;i++)
        {
            printf("%d ",a[i]);
        } 
        printf("\n");
            
    }
    
}

int main(int argc, char* argv[])
{
    int a[MAX_NUM];
    int n;    

    printf("Input total numbers: ");
    scanf("%d",&n);

    if( n > MAX_NUM ) n = MAX_NUM;
    
    for(int i = 0; i < n;i++)
    {
        scanf("%d",&a[i]);
    }
    
    printf("排序步骤:\n");
    shellsort(a,n);    
    
    return 0;
} 
View Code

 

  案例结果截图:

    

 

  希尔排序算法效率与稳定性分析

  在希尔排序中,由于开始插入n个待排序列的记录分成了d组,所以每组的记录数目将会减少。在数据量较少的时,利用直接插入排序的效率较高。随着反复分组排序,d值逐渐变小,每个分组中的待排序的记录数目将会变多,但此时记录的排列将会更加接近有序,所以利用直接插入排序不会降低排序的时间效率。

  上述过程中分组次数为log(n)。最好的情况,待排序序列已经排好序,在每次分组,直接插入排序的总时间复杂度为O(n),算法时间复杂度为O(nlog(n))。其他情况的复杂度分析相对复杂很多,本人理解的也不是很透彻,书中介绍说最坏情况和平均时间复杂度也均为 O(nlog(n))。

  希尔排序使用与待排序列的元素数目较大的情况。在此情况下,希尔排序方法一般要比直接插入排序方法快。同直接插入排序一样,希尔排序也只需要一个记录大小的辅助空间,用于暂时记录当前待插入的记录。

  由于排序时分组的原因导致序列输入顺序与原始顺序不一致,关键字相同的元素在排序前后可能发生变化,因而希尔排序是一种不稳定的排序算法。

 

  注:主要参考彭军、向毅主编的 《数据结构与算法》

 

posted on 2013-10-21 11:13  surgewong  阅读(733)  评论(0编辑  收藏  举报