面試常考:排序算法(希爾排序)

系列文章
我用一張圖徹底理解了冒泡排序
通俗易懂講解 [圖解]選擇排序
我去,你竟然還不會插入排序

希爾排序介紹

對於大規模的數組,插入排序很慢,因爲它只能交換相鄰的元素,每次只能將逆序數量減少 1。希爾排序的出現就是爲了解決插入排序的這種侷限性,它通過交換不相鄰的元素,每次可以將逆序數量減少大於 1。

希爾排序使用插入排序對間隔 gap 的序列進行排序。通過不斷減小 gap,最後令 gap=1,就可以使得整個數組是有序的。

下面以數列{80,30,60,40,20,10,50,70}爲例,演示它的希爾排序過程。

第1趟:(gap=4)
在這裏插入圖片描述
當gap=4時,意味着將數列分爲4個組: {80,20},{30,10},{60,50},{40,70}。 對應數列: {80,30,60,40,20,10,50,70}

對這4個組分別進行排序,排序結果: {20,80},{10,30},{50,60},{40,70}。 對應數列: {20,10,50,40,80,30,60,70}

第2趟:(n=2)
在這裏插入圖片描述
當gap=2時,意味着將數列分爲2個組:{20,50,80,60}, {10,40,30,70}。 對應數列: {20,10,50,40,80,30,60,70}
注意:{20,50,80,60}實際上有兩個有序的數列{20,80}和{50,60}組成。
{10,40,30,70}實際上有兩個有序的數列{10,30}和{40,70}組成。
對這2個組分別進行排序,排序結果:{20,50,60,80}, {10,30,40,70}。 對應數列: {20,10,50,30,60,40,80,70}

在這裏插入圖片描述
在上面的希爾排序中,首先要選取步長gap的值。選取了gap之後,就將數列分成了gap個組,對於每一個組都執行直接插入排序。在排序完所有的組之後,將gap的值減半;繼續對數列進行分組,然後進行排序。重複這樣的操作,直到gap<0爲止。此時,數列也就是有序的了。

約定

待排序的元素需要實現 Java 的 Comparable 接口,該接口有 compareTo() 方法,可以用它來判斷兩個元素的大小關係。

使用輔助函數 less() 和 swap() 來進行比較和交換的操作,使得代碼的可讀性和可移植性更好。

排序算法的成本模型是比較和交換的次數。

package 算法.排序;/*
作者     :XiangLin
創建時間 :15/05/2020 17:17
文件     :Sort.java
IDE      :IntelliJ IDEA
*/

public abstract class Sort<T extends Comparable<T>>{
    public abstract void sort(T[] nums);

    protected boolean less(T v, T w){
        return v.compareTo(w) < 0;
    }

    protected void swap(T[] a,int i ,int j){
        T t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

代碼

package 算法.排序;/*
作者     :XiangLin
創建時間 :23/05/2020 22:18
文件     :Shell.java
IDE      :IntelliJ IDEA
*/

public class Shell  <T extends Comparable<T>> extends Sort<T> {
    @Override
    public void sort(T[] nums) {
        int N = nums.length;
        int gap = 1;

        while (gap < N / 3){
            gap = 3 * gap + 1;
        }
        while (gap >= 1){
            for (int i = gap;i < N ; i ++){
                for (int j = i;j >= gap && less(nums[j],nums[j - gap]);j -= gap){
                    swap(nums,j,j-gap);
                }
            }
            gap = gap/ 3;
        }
    }
    public static void main(String[] args) {
        Integer[] nums = {52,63,14,59,68,35,8,67,45,99};
        System.out.println("原數組:");
        for(int i :nums){
            System.out.print(i+" ");
        }
        System.out.println();
        Shell s = new Shell();
        s.sort(nums);

        System.out.println("排序後:");
        for(int i :nums){
            System.out.print(i+" ");
        }
    }
}

在這裏插入圖片描述

總結

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

另外博主收藏這些年來看過或者聽過的一些不錯的常用的上千本書籍,沒準你想找的書就在這裏呢,包含了互聯網行業大多數書籍和麪試經驗題目等等。有人工智能系列(常用深度學習框架TensorFlow、pytorch、keras。NLP、機器學習,深度學習等等),大數據系列(Spark,Hadoop,Scala,kafka等),程序員必修系列(C、C++、java、數據結構、linux,設計模式、數據庫等等)以下是部分截圖
在這裏插入圖片描述

更多文章見本原創微信公衆號「五角錢的程序員」,我們一起成長,一起學習。一直純真着,善良着,溫情地熱愛生活。關注回覆【電子書】即可領取哦

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章