排序算法之希尔排序

算法描述:

     先取一个小于n的整数d1作为第一个步长,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个步长d2<d1重复上述的分组和排序,直至所取的步长dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法。

       步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

Donald Shell 最初建议步长选择为\frac{n}{2}并且对步长取半直到步长达到 1,但还有其他的步长可以达到更好的效果


算法度量:

数据结构     数组
最差时间复杂度     根据步长序列的不同而不同。 已知最好的: O(n\log^2 n)
最优时间复杂度     O(n)
平均时间复杂度     根据步长序列的不同而不同。
最差空间复杂度     O(n)
最佳算法     非最佳算法


源码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>

void print_ary( int * ary, unsigned int len )
{
    while( len-- > 0 ) {
        printf("%d ", *ary++ );    
    }
    putchar('\n');
}

void create_rondom_number(int **parray, unsigned int number)
{
    struct timeval tpstart;
    unsigned int i =0;

    if (NULL != *parray)
    {
        return;
    }

    *parray = (int *)malloc(sizeof(unsigned int) * number);
    (void)memset(*parray, 0, sizeof(unsigned int) * number);
    
    gettimeofday(&tpstart,NULL);

    //srandom(time(NULL));
    srandom(tpstart.tv_usec);

    for (i=0; i<number; ++i)
    {
        //(*parray)[i] = random()%number; // range is [0, number-1] 
        //(*parray)[i] = random()%(b-a) + a; //range is [a, b)
        ((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]
    }
}

void shell_sort(int a[], int n)
{
    int gap = 0;
    int i, j, temp; 

    while (gap<=n)
    {
        gap = gap * 3 + 1;
    } 

    printf("gap=%d\n", gap);

    while (gap > 0) 
    {
        /*对gap列数同时进行插入排序,因为插入排序开始假定第一个数是已经排好的,
         * 要从第二个数开始与前边的数进行比较。同理对gap列数同时进行插入排序时,
         * 也认为第一列的数是已经排完序的,要从第二列开始与前边的数进行比较,
         * 第二列数即地gap个元素, 注意:不是排完第一列再排第二列,而是同时排,
         * 即不是排完0,gap,2gap,3gap...,再排1,gap+1,2gap+2,3gap+3...
         * 而是从gap,gap+1,gap+3至n挨个列交替的进行排序 */

        for ( i = gap; i < n; i++ ) 
        {
            temp = a[i];//将a[i]列的即将插入到前边的数暂存到temp中             
            a[i] = 10000;//调试代码
            j = i - gap;//与a[i]这一列数的前一个元素开始比较

            printf("\n\ntemp=a[%d]=%d, j=%d gap=%d: ", i, temp, j, gap); print_ary(a, n);

            /*依次与a[i]列的前边每个数进行比较*/
            while (( j >= 0 ) && ( a[j] > temp ))
            {

                printf("a[%d]=%d move back to a[%d], a[%d] is idle: ", j, a[j], j+gap, j);

               /* a[i]列的前一个元素比temp大,则要将此数往后移一个位置 */
                a[j + gap] = a[j]; //将比temp大的往后移

                a[j] = 10000;//调试代码

                j = j - gap;

                print_ary(a, n);
                printf("--next element j=%d\n", j);
            }

            a[j + gap] = temp; //插入到比temp小的数的后边

            printf("temp=%d insert to a[%d]: ", temp, j+gap); print_ary(a, n);
        }

        gap = ( gap - 1 ) / 3;

    } 
}

int main( int argc, char ** argv )
{

    int *pary = NULL;

    if (argc !=2)
    {
        printf("\nUsage: %s Number\n", argv[0]); 
        return -1;
    }

    create_rondom_number(&pary, (unsigned int)atoi(argv[1]));    

    printf("\n\nrandom number: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );

    printf("Start sortting: \n");
    shell_sort( pary, (unsigned int)atoi(argv[1]));

    printf("\n\nafter sorted: ");
    print_ary( pary, (unsigned int)atoi(argv[1]) );
    
    return 0;
}


运行结果:

[root@localhost sort]# ./shell 10           


random number: 10 2 1 4 10 4 1 4 10 7
Start sortting:
gap=13


temp=a[4]=10, j=0 gap=4: 10 2 1 4 10000 4 1 4 10 7
temp=10 insert to a[4]: 10 2 1 4 10 4 1 4 10 7


temp=a[5]=4, j=1 gap=4: 10 2 1 4 10 10000 1 4 10 7
temp=4 insert to a[5]: 10 2 1 4 10 4 1 4 10 7


temp=a[6]=1, j=2 gap=4: 10 2 1 4 10 4 10000 4 10 7
temp=1 insert to a[6]: 10 2 1 4 10 4 1 4 10 7


temp=a[7]=4, j=3 gap=4: 10 2 1 4 10 4 1 10000 10 7
temp=4 insert to a[7]: 10 2 1 4 10 4 1 4 10 7


temp=a[8]=10, j=4 gap=4: 10 2 1 4 10 4 1 4 10000 7
temp=10 insert to a[8]: 10 2 1 4 10 4 1 4 10 7


temp=a[9]=7, j=5 gap=4: 10 2 1 4 10 4 1 4 10 10000
temp=7 insert to a[9]: 10 2 1 4 10 4 1 4 10 7


temp=a[1]=2, j=0 gap=1: 10 10000 1 4 10 4 1 4 10 7
a[0]=10 move back to a[1], a[0] is idle: 10000 10 1 4 10 4 1 4 10 7
--next element j=-1
temp=2 insert to a[0]: 2 10 1 4 10 4 1 4 10 7


temp=a[2]=1, j=1 gap=1: 2 10 10000 4 10 4 1 4 10 7
a[1]=10 move back to a[2], a[1] is idle: 2 10000 10 4 10 4 1 4 10 7
--next element j=0
a[0]=2 move back to a[1], a[0] is idle: 10000 2 10 4 10 4 1 4 10 7
--next element j=-1
temp=1 insert to a[0]: 1 2 10 4 10 4 1 4 10 7


temp=a[3]=4, j=2 gap=1: 1 2 10 10000 10 4 1 4 10 7
a[2]=10 move back to a[3], a[2] is idle: 1 2 10000 10 10 4 1 4 10 7
--next element j=1
temp=4 insert to a[2]: 1 2 4 10 10 4 1 4 10 7


temp=a[4]=10, j=3 gap=1: 1 2 4 10 10000 4 1 4 10 7
temp=10 insert to a[4]: 1 2 4 10 10 4 1 4 10 7


temp=a[5]=4, j=4 gap=1: 1 2 4 10 10 10000 1 4 10 7
a[4]=10 move back to a[5], a[4] is idle: 1 2 4 10 10000 10 1 4 10 7
--next element j=3
a[3]=10 move back to a[4], a[3] is idle: 1 2 4 10000 10 10 1 4 10 7
--next element j=2
temp=4 insert to a[3]: 1 2 4 4 10 10 1 4 10 7


temp=a[6]=1, j=5 gap=1: 1 2 4 4 10 10 10000 4 10 7
a[5]=10 move back to a[6], a[5] is idle: 1 2 4 4 10 10000 10 4 10 7
--next element j=4
a[4]=10 move back to a[5], a[4] is idle: 1 2 4 4 10000 10 10 4 10 7
--next element j=3
a[3]=4 move back to a[4], a[3] is idle: 1 2 4 10000 4 10 10 4 10 7
--next element j=2
a[2]=4 move back to a[3], a[2] is idle: 1 2 10000 4 4 10 10 4 10 7
--next element j=1
a[1]=2 move back to a[2], a[1] is idle: 1 10000 2 4 4 10 10 4 10 7
--next element j=0
temp=1 insert to a[1]: 1 1 2 4 4 10 10 4 10 7


temp=a[7]=4, j=6 gap=1: 1 1 2 4 4 10 10 10000 10 7
a[6]=10 move back to a[7], a[6] is idle: 1 1 2 4 4 10 10000 10 10 7
--next element j=5
a[5]=10 move back to a[6], a[5] is idle: 1 1 2 4 4 10000 10 10 10 7
--next element j=4
temp=4 insert to a[5]: 1 1 2 4 4 4 10 10 10 7


temp=a[8]=10, j=7 gap=1: 1 1 2 4 4 4 10 10 10000 7
temp=10 insert to a[8]: 1 1 2 4 4 4 10 10 10 7


temp=a[9]=7, j=8 gap=1: 1 1 2 4 4 4 10 10 10 10000
a[8]=10 move back to a[9], a[8] is idle: 1 1 2 4 4 4 10 10 10000 10
--next element j=7
a[7]=10 move back to a[8], a[7] is idle: 1 1 2 4 4 4 10 10000 10 10
--next element j=6
a[6]=10 move back to a[7], a[6] is idle: 1 1 2 4 4 4 10000 10 10 10
--next element j=5
temp=7 insert to a[6]: 1 1 2 4 4 4 7 10 10 10


after sorted: 1 1 2 4 4 4 7 10 10 10
[root@localhost sort]#


参考:

http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F

http://baike.baidu.com/view/178698.htm


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值