希爾排序增量研究


        上一篇介紹了希爾排序,它又被稱為縮小增量排序,這就說明了增量在希爾排序中的重要性。

        本篇使用四組不同的增量,通過統計排序的比較次數、移動次數、執行時間,來討論不同的增量對希爾排序效率的影響。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM