zoukankan      html  css  js  c++  java
  • 希尔排序增量研究

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

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

            选取的增量: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

  • 相关阅读:
    Android Gallery和ImageSwitcher同步自动(滚动)播放图片库
    Android PullToRefreshListView和ViewPager的结合使用
    AndroidTagView云标签
    Android 两步搞定Fragment的返回键
    Android Fragment数据传递与数据回显
    Glide加载圆形图片第一次只显示默认图片
    Android 自定义EditText实现类iOS风格搜索框
    TabLayout中Indicator的样式修改
    Kali linux2.0里Metasploit的服务类型探测
    Kali linux 2016.2(Rolling)中的Nmap的端口扫描功能
  • 原文地址:https://www.cnblogs.com/Y-oung/p/7805984.html
Copyright © 2011-2022 走看看