數據結構 7 基礎排序算法詳解 雞尾酒排序法、瞭解鐘擺排序實現

前言

上節,我們已經通過對冒泡算法的優化、能夠達到我們預想的結果。比較次數的減少、本節將繼續在冒泡排序的基礎上進行優化、能夠達到剛好的效果。

雞尾酒排序 🍸

爲什麼叫雞尾酒排序呢?可能這個名字起得比較特殊。它是基於冒泡排序做了一些小小的改動。也叫做快樂鐘擺排序 現在,大家的腦子裏肯定會想到一個古老的鐘擺。。。。。

左搖一下、右搖一下、重複不止

現在請記住這個場景。我們來學習一下這個雞尾酒排序爲何方神聖!

冒泡排序特點

從左往右、依次循環比較、一遍將一個大元素推到最右側。

雞尾酒排序特點

  1. 將原有的單向改爲 雙向比較
  2. 每次循環則將最小元素和最大元素分別推至左右兩側

畫圖理解

準備一個數組 [49, 38, 65, 97, 76, 13, 27, 49]

image.png

鐘擺循環1開始 從右至左

1、本次比較27<49則無需改變循序。
image.png

2、本次比較13<27則無需改變循序。
image.png

3、本次比較76<13則需要交換位置。
image.png

image.png

4、直到比較到最左側。。。(這裏省略幾個步驟)
image.png

我們發現,這個最小的元素13 已經被確認出來了。

鐘擺循環2開始 從左至右

  1. 13<49 則不改變位置。繼續向下移步
    image.png

  2. 49>38 則需要交換位置。交換位置後,繼續下一步
    image.png

  3. 49<65 則位置不改變,繼續向下一步。
    image.png

  4. 省略一些步驟。直到比較完最後一個元素。最大的一個元素97 已經被確認出來了。
    image.png

代碼示例

public static void sort4(int[] array) {

    int temp = 0;
    int allChange = 0;
    /**
     * 外層循環用於控制程序總體循環次數
     */
    for (int i = 0; i < array.length / 2; i++) {

        /**
         * 有無交換元素標記
         */
        boolean isChange = true;

        //從左向右擺動
        for (int j = i; j < array.length - i - 1; j++) {

            if (array[j] > array[j + 1]) {

                //交換元素
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;

                isChange = false;
            }
            allChange++;
        }

        if (isChange) break;

        isChange = true;
        //從右向左擺動
        for (int g = array.length - i - 1; g > i; g--) {

            if (array[g] < array[g - 1]) {

                temp = array[g];

                array[g] = array[g-1];
                array[g-1] = temp;

                isChange = false;
            }
            allChange++;
        }
        if (isChange) break;
    }
    System.out.println(Arrays.toString(array));
    System.out.println("總體比較次數:"+allChange);
}

結果如下:

[13, 27, 38, 49, 49, 65, 76, 97]
總體比較次數:30

通過觀察我們發現,當前算法的比較次數還是相對來說較多的。外層大循環運行減少一半、但是內層兩個小循環還是需要注意的。有什麼辦法可以優化一下呢?我們可以採用之前的思路。通過設置有序長度 的方式來減少內層循環次數、已達到我們優化的目的。

有序優化

其實說白了,就是在發生變化的時候記錄當前位置,下次循環到本次記錄的位置停止則可以了。
通過兩個邊界變量 leftBorderrightBorder 控制程序比較位置的終止。

左循環從左邊界比較到右邊界停止
右循環從右邊界比較到左邊界停止

public static void sort5(int[] array) {


    int temp = 0;
    int allChange = 0;

    //記錄左邊界
    int leftBorder = 0;
    //右邊界
    int rightBorder = array.length - 1;
    //左邊發生變化的位置
    int leftChangeIndex = 0;
    //右邊發生變化的位置
    int rightChangeIndex = 0;

    /**
     * 外層循環用於控制程序總體循環次數
     */
    for (int i = 0; i < array.length / 2; i++) {

        /**
         * 有無交換元素標記
         */
        boolean isChange = true;

        //從左向右擺動
        for (int j = leftBorder; j < rightBorder; j++) {

            if (array[j] > array[j + 1]) {

                //交換元素
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;

                isChange = false;

                //記錄右邊邊界
                rightChangeIndex = j;
            }
            allChange++;
        }
        //用於下次循環終止
        rightBorder = rightChangeIndex;

        if (isChange) break;

        isChange = true;
        //從右向左擺動
        for (int g = rightBorder; g > leftBorder; g--) {

            if (array[g] < array[g - 1]) {

                temp = array[g];

                array[g] = array[g-1];
                array[g-1] = temp;

                isChange = false;
                //記錄左邊界
                leftChangeIndex = g;

            }
            allChange++;
        }
        leftBorder = leftChangeIndex;

        if (isChange) break;
    }
    System.out.println(Arrays.toString(array));
    System.out.println("總體比較次數:"+allChange);
}
--------------
[13, 27, 38, 49, 49, 65, 76, 97]
總體比較次數:27

小結

至此我們已經學習了有關的三個排序方式、包括最基礎的冒泡排序、優化冒泡排序。最終的冒泡排序。通過鐘擺思想實現的雞尾酒排序法。越來覺得一個小小的排序,通過學習後發現,竟然有很多有意思的地方。

參考

https://mp.weixin.qq.com/s/CoVZrvis6BnxBQgQrdc5kA

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