希爾排序(交換法和位移法)


 希爾排序是希爾(Donald Shell)於1959年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之后的一個更高效的版本,也稱為縮小增量排序,同時該算法是沖破O(n2)的第一批算法之一。本文會以圖解的方式詳細介紹希爾排序的基本思想及其代碼實現。

基本思想

  希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。

  簡單插入排序很循規蹈矩,不管數組分布是怎么樣的,依然一步一步的對元素進行比較,移動,插入,比如[5,4,3,2,1,0]這種倒序序列,數組末端的0要回到首位置很是費勁,比較和移動元素均需n-1次。而希爾排序在數組中采用跳躍式分組的策略,通過某個增量將數組元素划分為若干組,然后分組進行插入排序,隨后逐步縮小增量,繼續按組進行插入排序操作,直至增量為1。希爾排序通過這種策略使得整個數組在初始階段達到從宏觀上看基本有序,小的基本在前,大的基本在后。然后縮小增量,到增量為1時,其實多數情況下只需微調即可,不會涉及過多的數據移動。

  我們來看下希爾排序的基本步驟,在此我們選擇增量gap=length/2,縮小增量繼續以gap = gap/2的方式,這種增量選擇我們可以用一個序列來表示,{n/2,(n/2)/2...1},稱為增量序列。希爾排序的增量序列的選擇與證明是個數學難題,我們選擇的這個增量序列是比較常用的,也是希爾建議的增量,稱為希爾增量,但其實這個增量序列不是最優的。此處我們做示例使用希爾增量。

代碼實現

package com.cai.math;

import org.springframework.http.converter.json.GsonBuilderUtils;

import java.util.Arrays;

/**
 * 希爾排序 :希爾排序也是一種插入排序,它是簡單插入排序經過改進之后的一個更高效的版本,也稱為縮小增量排序
 * 實現:1.希爾排序(交換法)
 *      2.希爾排序(位移法)--效率更高
 */
public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        sort2(arr);
    }

    /**
     * 交換法
     * @param arr
     */
    public static void sort1(int[] arr){
        //gap逐步減小增量(每次 arr.length/2)
        for (int gap =arr.length/2;gap>0;gap=gap/2) {
            //插入排序把數組分成兩部分:有序部分,無序部分(這里把gap前的當成有序部分,即分組后的每組第一個)
            for (int j = gap; j <arr.length ; j++) {
                //重組有序部分
                for (int t = j; t >=0 ; t-=gap) { //插入時候 從后到前 和 從前到后 插略有區別(個人理解)
                    if(t-gap>=0 && arr[t]<arr[t-gap]){ //逐步往前比較,小的放前(通過交換位置)
                        int temp = arr[t];
                        arr[t] = arr[t-gap];
                        arr[t-gap] = temp;
                    }
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
    /**
     * 位移法
     */
    public static void sort2(int[] arr){
        //gap逐步減小增量(每次 arr.length/2)
        for (int gap =arr.length/2;gap>0;gap=gap/2) {
            //插入排序把數組分成兩部分:有序部分,無序部分(這里把gap前的當成有序部分,即分組后的每組第一個)
            for (int j = gap; j <arr.length ; j++) {
                int k =j;
                int temp = arr[j];
                //重組有序部分
                //判斷有序部分 最后一個,如果比當前值小就沒有必要重新排序
                if(arr[k]<arr[k-gap]){
                    while (k-gap>=0 && arr[k-gap]>temp){
                        arr[k]=arr[k-gap]; //大於temp的整體向后移動
                        k-=gap;
                    }
                    //找到適合的位置把 最開始 arr[j]的值插入進去
                    arr[k] = temp;//不能直接用 j,避免和上一層循環沖突
                }

            }
        }
        System.out.println(Arrays.toString(arr));
    }

}

 

總結

  本文介紹了希爾排序的基本思想及其代碼實現,希爾排序中對於增量序列的選擇十分重要,直接影響到希爾排序的性能。我們上面選擇的增量序列{n/2,(n/2)/2...1}(希爾增量),其最壞時間復雜度依然為O(n2),一些經過優化的增量序列如Hibbard經過復雜證明可使得最壞時間復雜度為O(n3/2)。希爾排序的介紹到此為止,關於其他排序算法的介紹也會陸續更新,謝謝支持。


免責聲明!

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



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