希爾排序算法


  原博主:https://www.jianshu.com/p/d730ae586cf3

1,希爾排序概述

   希爾排序(shell Sort) 是插入排序的一種算法,是對直接插入排序的幾個優化,也稱縮小增量排序。

    注意:1,希爾排序是非穩定性排序算法;

                2,為了方便記憶算法,我習慣將其記作 “三層for循環+if” ------** for(for(for(if)))**)

 2,比較直接插入排序算法:

      希爾排序是基於直接插入排序的以下兩點性質而提出的改進方法:

      1,插入排序在對幾乎已經排好序的數據操作時,效率高,即可達到線性排序的效率。

      2,插入排序一般是低效的,因為插入排序每次只能將數據移動一位。

3,希爾排序的思想

     希爾排序是將待排序的數組元素 按下標的一定增量分組,分成多個子序列,然后對多個子序列進行直接插入排序算法排序;

然后依次縮減增量在進行排序,直到增量為1時,進行最后一次直接插入排序,排序結束。

理解過程:

**增量d 的范圍: **1<= d < 待排序數組的長度 (d 需為 int 值)
**增量的取值: **一般的初次取序列(數組)的一半為增量,以后每次減半,直到增量為1。
第一個增量=數組的長度/2,
第二個增量= 第一個增量/2,
第三個增量=第二個增量/2,
以此類推,最后一個增量=1。

好的增量序列的共同特征:
① 最后一個增量必須為1;
② 應該盡量避免序列中的值(尤其是相鄰的值)互為倍數的情況。

三、原理過程圖解

四、時間復雜度

**希爾排序的執行時間依賴於增量序列。 **
希爾排序耗時的操作有:比較 + 后移賦值。

時間復雜度情況如下:(n指待排序序列長度)
1) 最好情況:序列是正序排列,在這種情況下,需要進行的比較操作需(n-1)次。后移賦值操作為0次。即O(n)
2) 最壞情況:O(nlog2n)。
3) 漸進時間復雜度(平均時間復雜度):O(nlog2n)

 白話理解:

         希爾排序是按照不同步長對元素進行插入排序,當剛開始元素很無序的時候,步長最大,所以插入排序的元素個數很少,速度很快;當元素基本有序了,步長很小,插入排序對於有序的序列效率很高。所以,希爾排序的時間復雜度會比O(n²)好一些。
希爾算法的性能與所選取的增量(分組長度)序列有很大關系。只對特定的待排序記錄序列,可以准確地估算比較次數和移動次數。想要弄清比較次數和記錄移動次數與增量選擇之間的關系,並給出完整的數學分析,至今仍然是數學難題。

希爾算法在最壞的情況下和平均情況下執行效率相差不是很多,與此同時快速排序在最壞的情況下執行的效率會非常差。希爾排序沒有快速排序算法快,因此中等大小規模表現良好,對規模非常大的數據排序不是最優選擇。
注:專家們提倡,幾乎任何排序工作在開始時都可以用希爾排序,若在實際使用中證明它不夠快,再改成快速排序這樣更高級的排序算法。)

 五,穩定性分析:

    由於多次插入排序,我們知道一次插入排序是穩定的,不會改變相同元素的相對順序,但在不同的插入排序過程中,相同的元素可能在各自的插入排序中移動,最后其穩定性就會被打亂

所以希爾排序是不穩定的。

 六,核心代碼(升序排序為例)。

   (注:為方便記憶算法,我習慣將其記作“三層for循環+if ” ------for(for(for(if))))

 //希爾排序  升序
        for (int d = arr.length / 2;d>0;d /= 2){ //d:增量  7   3   1
            for (int i = d; i < arr.length; i++){ 
                
                //【插入排序 可以提取出來】
                
                //i:代表即將插入的元素角標,作為每一組比較數據的最后一個元素角標 
                //j:代表與i同一組的數組元素角標(前一個元素角標)
                for (int j = i-d; j>=0; j-=d){ //在此處-d 為了避免下面數組角標越界 j=j-d
                    
                    if (arr[j] > arr[j + d]) {// j+d 代表即將插入的元素所在的角標
                        
                        //符合條件,插入元素(交換位置)
                        int temp = arr[j];
                        arr[j] = arr[j + d];
                        arr[j + d] = temp;
                    }
                }
                //====================================
                
            } 
        }
        return arr;
    }

測試所有源碼:

public class ShellSorts {

    public static void main(String[] args) {

        // 聲明一個數組
        int[] arr = new int[] { 3, 2, 5, 4, 1 };
        System.out.println("原數組:" + Arrays.toString(arr));
        System.out.println("排序后" + Arrays.toString(insertionSort(arr)));

    }

    /**
     * 希爾排序思路 
     * 1,先判斷數組為空或者只有一個元素的情況 
     * 2,確定截取增量長度=數組長度/2(循環) 直到增量為1
     * 3,對每一個增量進行排序【一般采用直接插入排序】
     * 4,接着遍歷下一層增量,直到增量為1,排序完成
     * @param arr
     * @return
     */
    // 簡化希爾排序
    public static int[] insertionSort(int[] arr) {
        // 數組長度小於等於1的情況
        if (arr == null || arr.length <= 1) {
            return arr;
        }

        // 希爾排序 升序
        for (int d = arr.length / 2; d > 0; d /= 2) { // d:增量 7 3 1
            for (int i = d; i < arr.length; i++) {

                // 【插入排序 可以提取出來】

                // i:代表即將插入的元素角標,作為每一組比較數據的最后一個元素角標
                // j:代表與i同一組的數組元素角標(前一個元素角標)
                for (int j = i - d; j >= 0; j -= d) { // 在此處-d 為了避免下面數組角標越界
                                                        // j=j-d

                    if (arr[j] > arr[j + d]) {// j+d 代表即將插入的元素所在的角標

                        // 符合條件,插入元素(交換位置)
                        int temp = arr[j];
                        arr[j] = arr[j + d];
                        arr[j + d] = temp;
                    }
                }

            }
        }
        return arr;
    }

    // 算法提煉 兩元素位置交換方法
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    // 對於java自帶的Arrays.toString()方法的實現
    public static void printArray(int[] arr) {
        System.out.print("[");
        for (int x = 0; x < arr.length; x++) {
            if (x != arr.length - 1) {
                System.out.print(arr[x] + ", ");
            } else {
                System.out.println(arr[x] + "]");
            }

        }
    }

}

 


免責聲明!

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



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