希尔排序增量研究

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

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

        选取的增量: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)
h1 70899317 53401514 390 409
71248646 53751082 437
63125216 45628028 406
65709200 48211399 406
h2 58908538 47827463 328 367
57271566 46192005 360
58745050 47664214 422
58158118 47077871 359
h3 63337835 45942623 391 434
62261484 44866301 422
64507400 47112762 485
65932139 48537533 438
h4 67600938 56206667 359 398
62428374 51034112 390
67867685 56472626 453
63794589 52400141 391

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

        2、序列的元素个数改变

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

元素个数 增量h 比较次数 移动次数 执行时间(ms)
10000 h1 266301 151388 0
h2 242150 171389 0
h3 237881 129346 15
h4 238686 167816 0
100000 h1 4270009 2820476 32
h2 4174584 3267076 15
h3 3959590 2543037 32
h4 3867292 2941534 31
1000000 h1 66890878 49393622 422
h2 59190877 48110274 360
h3 59872906 42478486 406
h4 62805422 51410564 375
10000000 h1 1035250229 820261049 5301
h2 1167560154 1036812889 5532
h3 980127157 772150177 5294
h4 9659604955 854508598 5378

        从测试结果可以看出,不同长度的序列使用四个增量分别进行排序时,比较次数、移动次数、排序时长有一定差异。当元素个数较少时,增量为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

posted @ 2017-11-08 20:25  白杨树丶  阅读(2002)  评论(0编辑  收藏  举报