排序—希尔排序

希尔排序由多次插入排序组成,只是每次插入排序的增量不同。希尔排序使用一个增量序列 h_{1},h_{2},...,h_{t},这个增量序列可以是任意的,只要保证h_{1}=1.但不同的增量序列间存在更好的一个序列。在以增量h_{k}进行一次排序后,对于每一个位置i,有arr[i]\leq arr[i+hk](i+h_{k})没有越界),在使用 h_{1} 进行排序之后,整个数组就变得有序。

希尔增量:h_{t}选择为数组元素个数的一半,每执行完一次插入排序,就将增量缩小为它自身的一半,直到h_{1}=1.采用希尔增量的希尔排序时间复杂度为O(N^2)

Hibbard增量:h_{k}=2^{^{k}}-1\left \{ 1,3,7,15,... \right \},采用Hibbard增量的希尔排序时间复杂度为O(N^{\frac{3}{2}}),平均运行时间为O(N^{\frac{5}{4}}).

Sedgewick增量:h_{k}=max\left \{ 9*4^{i}-9*2^{i}+1,4^{j}-3*2^{j}+1 \right \},\left \{ 1,5,19,41,109,209,... \right \},采用Sedgewick增量的希尔排序时间复杂度为O(N^{\frac{4}{3}}),平均运行时间为O(N^{\frac{7}{6}}).

对于如下数组的排序:

2340532811520182627

使用希尔增量对数组进行排序:

h_{3}=5排序时,从数组下标 i=5 处开始排序(因为当i<5时,这个元素之前没有跟它间隔h_{3}的元素。也就是在这趟排序时,P的初值P=h_{3},并完成一次增量为h_{3}插入排序(也就是间隔为h_{3}元素之间的排序)。这次插入排序结果如下:

1520526272340183281

 h_{2}=2排序过程为:

P=2

5201526272340183281

p=3

5201526272340183281

p=4

5201526272340183281

p=5

5201523272640183281
5201523272640183281

p=6

5201523272640183281

p=7

5201523271840263281
5201518272340263281
5181520272340263281

p=8

5181520272332264081
5181520272332264081

p=9

5181520272332264081

h_{1}=1排序后的结果如下:

5151820232627324081

最后一次插入排序之后,数组就变得有序,虽然最后一次排序是一个标准的插入排序,而插入排序的时间复杂度为O(N^{2}),但由于最后一次排序之前,数组已经变得大体上有序,所以这次插入排序花费的时间并没有这么多。使用希尔增量的希尔排序性能并不是很好,使用Sedgewick增量的希尔排序的性能是更好的,并且在实践中使用Sedgewick增量的希尔排序要快于堆排序。(堆排序的时间复杂度为O(NlogN).

使用Sedgewick增量的希尔排序实现:

//将Sedgewick增量序列列出,以便使用
const int sedgewick[] = { 1, 5, 19, 41, 109, 209, 505, 929, 2161,
		3905, 8929, 16001, 36289, 64769, 146305,
		260609, 587521, 1045505, 2354689, 4188161,
		9427969, 16764929, 37730305, 67084289,
		150958081, 268386305, 603906049, 1073643521 };

//希尔排序
void shell_sort(int* arr,int size){
    int inc;//增量
    int i,j;
    int k;//用来选择Sedgewick增量
    for(k=1,inc=sedgewick[k];k>=0;k--){//根据数组元素的大小,找到不大于size-1的sedgewick增量的下标,如果是10个元素排序,则从5开始
        for(i=inc;i<size;i++){//从这里开始,下面的代码与插入排序的代码相似
            int tmp=arr[i];
            for(j=i;j>=inc&&arr[j-inc]>tmp;j--){
                arr[j]=arr[j-inc];
            }
            arr[j]=tmp;
        }
    }
}
        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值