希尔排序增量研究

        上一篇介绍了希尔排序,它又被称为缩小增量排序,这就说明了增量在希尔排序中的重要性。

        本篇使用四组不同的增量,通过统计排序的比较次数、移动次数、执行时间,来讨论不同的增量对希尔排序效率的影响。

        选取的增量:h1=N/2, N/4, N/8,……,1(每次增量减半)

                             h2=N/3, N/9, N/27,……,1(每次增量为原来的三分之一)

                             h3=2ⁿ-1 (h=1,3,7,……)(增量为奇数)

                             h4=(3ⁿ-1)/2 (h=1,4,13,……)

        1、保持序列元素个数不变

        保持序列元素个数为1000000,每次随机生成不同的序列,对四个增量分别做4组排序。

增量h比较次数移动次数执行时间(ms)平均时间(ms)
h17089931753401514390409
7124864653751082437
6312521645628028406
6570920048211399406
h25890853847827463328367
5727156646192005360
5874505047664214422
5815811847077871359
h36333783545942623391434
6226148444866301422
6450740047112762485
6593213948537533438
h46760093856206667359398
6242837451034112390
6786768556472626453
6379458952400141391

        从测试的结果来看,当序列元素个数相同时,对四种增量分别用生成的四组随机数排序时,它们的比较次数、移动次数以及执行时间等参数差别不大。因此可以认为对于待排序列的元素个数相同的情况下,基于以上四种增量的序列,希尔排序算法的时间复杂度差异不是很明显,执行效率差别不大。

        2、序列的元素个数改变

        使序列元素个数增加,分别取10000、100000、1000000、10000000,每次随机生成不同的序列,对四个增量分别排序。

元素个数增量h比较次数移动次数执行时间(ms)
10000h12663011513880
h22421501713890
h323788112934615
h42386861678160
100000h14270009282047632
h24174584326707615
h33959590254303732
h43867292294153431
1000000h16689087849393622422
h25919087748110274360
h35987290642478486406
h46280542251410564375
10000000h110352502298202610495301
h2116756015410368128895532
h39801271577721501775294
h496596049558545085985378

        从测试结果可以看出,不同长度的序列使用四个增量分别进行排序时,比较次数、移动次数、排序时长有一定差异。当元素个数较少时,增量为h2=N/3, N/9, N/27,……,1的希尔排序效率比其他增量略高;

当元素个数较多时,增量为h4=(3ⁿ-1)/2 (h=1,4,13,……)的希尔排序效率比其他增量略高。

        综上所述,希尔排序算法在不同增量下的执行效率也不尽相同,增量是影响希尔排序效率的重要因素。遗憾的是,虽然有很多论文专门研究过不同的增量对希尔排序的影响,但都无法证明某个增量是最好的。因此在使用希尔排序时,根据排序序列的大小,选取适当的增量对提高排序效率很有帮助。

        参考代码:以Java为例。

import java.util.Random;

/*
 * 希尔排序
 */

public class ShellSort {
    //增量h=N/2
    static long comp1 = 0;  //比较次数
    static long exch1 = 0;  //交换次数
    public static void sort1(int[] a) {
        int n = a.length;  //序列长度
        int h = n/2;  //初始增量h为序列长度的一半
        while (h >= 1) {
            for (int i = h; i < n; i++) {
                for (int j = i; j >= h; j -= h) {
                    comp1++;
                    if(a[j]<a[j-h]){
                        int swap = a[j];
                        a[j] = a[j-h];
                        a[j-h] = swap;
                        exch1++;
                    }else{
                        break;
                    }
                }
            }
            h /= 2;  //增量减半
        }
    }
    //增量h=N/3
    static long comp2 = 0;  //比较次数
    static long exch2 = 0;  //交换次数
    public static void sort2(int[] a) {
        int n = a.length;  //序列长度
        int h = n/3;  //初始增量h为序列长度的三分之一
        while (h >= 1) {
            for (int i = h; i < n; i++) {
                for (int j = i; j >= h; j -= h) {
                    comp2++;
                    if(a[j]<a[j-h]){
                        int swap = a[j];
                        a[j] = a[j-h];
                        a[j-h] = swap;
                        exch2++;
                    }else{
                        break;
                    }
                }
            }
            h /= 3;  //增量减为三分之一
        }
    }
    //增量h=2ⁿ-1 (h=1,3,7……)
    static long comp3 = 0;  //比较次数
    static long exch3 = 0;  //交换次数
    public static void sort3(int[] a) {
        int n = a.length;  //序列长度
        int h = 1;
        while (h < n/2) h = 2*h + 1;
        while (h >= 1) {
            for (int i = h; i < n; i++) {
                for (int j = i; j >= h; j -= h) {
                    comp3++;
                    if(a[j]<a[j-h]){
                        int swap = a[j];
                        a[j] = a[j-h];
                        a[j-h] = swap;
                        exch3++;
                    }else{
                        break;
                    }
                }
            }
            h /= 2;
        }
    }
    //增量h=(3ⁿ-1)/2 (h=1,4,13……)
    static long comp4 = 0;  //比较次数
    static long exch4 = 0;  //交换次数
    public static void sort4(int[] a) {
        int n = a.length;  //序列长度
        int h = 1;
        while (h < n/3) h = 3*h + 1;
        while (h >= 1) {
            for (int i = h; i < n; i++) {
                for (int j = i; j >= h; j -= h) {
                    comp4++;
                    if(a[j]<a[j-h]){
                        int swap = a[j];
                        a[j] = a[j-h];
                        a[j-h] = swap;
                        exch4++;
                    }else{
                        break;
                    }
                }
            }
            h /= 3;
        }
    }
    public static void main(String[] args) {
        Random random = new Random();
        int[] arg = new int[10000];
        for(int n=0;n<10000;n++){  //从[0-10000]中生成10000个随机数
            arg[n] = random.nextInt(10000);
        }
        int[] arg1 = new int[arg.length];
        int[] arg2 = new int[arg.length];
        int[] arg3 = new int[arg.length];
        int[] arg4 = new int[arg.length];
        for(int n=0;n<arg.length;n++){  //将随机生成的数组复制到4个数组中
            arg1[n] = arg[n];
            arg2[n] = arg[n];
            arg3[n] = arg[n];
            arg4[n] = arg[n];
        }
        //分别对4个元素相等的数组用4个不同增量排序
        long startTime1 = System.currentTimeMillis();  //获取开始时间
        sort1(arg1);
        long endTime1 = System.currentTimeMillis();  //获取结束时间
        long startTime2 = System.currentTimeMillis();  //获取开始时间
        sort2(arg2);
        long endTime2 = System.currentTimeMillis();  //获取结束时间
        long startTime3 = System.currentTimeMillis();  //获取开始时间
        sort3(arg3);
        long endTime3 = System.currentTimeMillis();  //获取结束时间
        long startTime4 = System.currentTimeMillis();  //获取开始时间
        sort4(arg4);
        long endTime4 = System.currentTimeMillis();  //获取结束时间
        System.out.println("数组长度:"+arg.length);
        System.out.println("增量h=N/2的比较次数:          "+comp1+" 交换次数:"+exch1+" 排序时长:"+(endTime1-startTime1)+"ms");
        System.out.println("增量h=N/3的比较次数:          "+comp2+" 交换次数:"+exch2+" 排序时长:"+(endTime2-startTime2)+"ms");
        System.out.println("增量h=2ⁿ-1的比较次数:        "+comp3+" 交换次数:"+exch3+" 排序时长:"+(endTime3-startTime3)+"ms");
        System.out.println("增量h=(3ⁿ-1)/2的比较次数:"+comp4+" 交换次数:"+exch4+" 排序时长:"+(endTime4-startTime4)+"ms");
    }
}

         执行结果:

数组长度:10000
增量h=N/2的比较次数:          265465 交换次数:150579 排序时长:0ms
增量h=N/3的比较次数:          230360 交换次数:159712 排序时长:0ms
增量h=2ⁿ-1的比较次数:        238035 交换次数:129679 排序时长:15ms
增量h=(3ⁿ-1)/2的比较次数:227429 交换次数:156614 排序时长:0ms

 

         转载请注明出处 http://www.cnblogs.com/Y-oung/p/7805984.html

        工作、学习、交流或有任何疑问,请联系邮箱:yy1340128046@163.com

转载于:https://www.cnblogs.com/Y-oung/p/7805984.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值