1. 程式人生 > >排序演算法之雞尾酒排序

排序演算法之雞尾酒排序

原文:微信公眾號:程式設計師小灰——什麼是雞尾酒排序

一、雞尾酒排序

雞尾酒排序是氣泡排序的一種變形。它與氣泡排序的不同之處在於排序時是以雙向在序列中進行排序。

二、原理

雞尾酒排序的原理跟氣泡排序差不多,只不過氣泡排序每一輪的比較都是從左至右依次比較,而雞尾酒排序則是一輪從左至右比較,下一輪從右至左比較。

假如有一個這樣的陣列:{2, 3, 4, 5, 6, 7, 8, 1},如果按照氣泡排序的比較方式,會是這樣的流程:

可以看到其實每次移動的只是元素 1,如果按照氣泡排序的原理,一共需要進行 7 輪比較,顯然這是可以進行優化的,在第 1 輪比較後,第 2 輪則從右至左比較,將最小的元素交換到最左側,這樣就可以減少比較的總次數:

三、程式碼實現

    public static int[] cockTailSort1(int[] origin) {
        if (origin == null || origin.length == 0) {
            return new int[]{};
        }
        System.out.println("origin--->" + Arrays.toString(origin));
        int index = 0;
        for (int i = 0; i < origin.length - 1; i++) {
            boolean isSorted = true;
            if (i % 2 == 0) {
                for (int j = 0; j < origin.length - i - 1; j++) {
                    if (origin[j] > origin[j + 1]) {
                        int temp = origin[j];
                        origin[j] = origin[j + 1];
                        origin[j + 1] = temp;
                        isSorted = false;
                    }
                    index++;
                }
            } else {
                for (int j = origin.length - i - 1; j > 0; j--) {
                    if (origin[j - 1] > origin[j]) {
                        int temp = origin[j - 1];
                        origin[j - 1] = origin[j];
                        origin[j] = temp;
                        isSorted = false;
                    }
                    index++;
                }
            }
            System.out.println("第" + (i + 1) + "次比較後" + "--->" + Arrays.toString(origin) + ",isSorted--->" + isSorted);
            if (isSorted) {
                break;
            }
        }
        System.out.println("index--->" + index);
        System.out.println("sortedArray--->" + Arrays.toString(origin));
        return origin;
    }

使用測試程式碼執行一遍:

    @Test
    public void testCockTailSort1() {
        // int[] intArray = new int[10];
        // for (int i = 0; i < intArray.length; i++) {
        // intArray[i] = new Random().nextInt(100);
        // }
        int[] intArray = new int[]{2, 3, 4, 5, 6, 7, 8, 1};
        cockTailSort1(intArray);
    }

執行結果如下:

可以看到相較於氣泡排序,總的比較次數已經從 8 次減少到了 3 次。

四、優化

同樣,雞尾酒排序也可以像氣泡排序一樣進行優化,記錄左右比較位置,減少內迴圈次數:

    public static int[] cockTailSort(int[] origin) {
        if (origin == null || origin.length == 0) {
            return new int[]{};
        }
        // 記錄右側最後一次交換的位置
        int lastRightExchangeIndex = 0;
        // 記錄左側最後一次交換的位置
        int lastLeftExchangeIndex = 0;
        // 無序數列的右邊界,每次比較只需要比到這裡為止
        int rightSortBorder = origin.length - 1;
        // 無序數列的左邊界,每次比較只需要比到這裡為止
        int leftSortBorder = 0;
        System.out.println("origin--->" + Arrays.toString(origin));
        int index = 0;
        for (int i = 0; i < origin.length - 1; i++) {
            boolean isSorted = true;
            if (i % 2 == 0) {
                System.out.print("從 " + leftSortBorder + " 比較到 " + rightSortBorder + ",");
                for (int j = leftSortBorder; j < rightSortBorder; j++) {
                    if (origin[j] > origin[j + 1]) {
                        int temp = origin[j];
                        origin[j] = origin[j + 1];
                        origin[j + 1] = temp;
                        isSorted = false;
                        lastRightExchangeIndex = j;
                    }
                    index++;
                }
            } else {
                System.out.print("從 " + rightSortBorder + " 比較到 " + leftSortBorder + ",");
                for (int j = rightSortBorder; j > leftSortBorder; j--) {
                    if (origin[j] < origin[j - 1]) {
                        int temp = origin[j];
                        origin[j] = origin[j - 1];
                        origin[j - 1] = temp;
                        isSorted = false;
                        lastLeftExchangeIndex = j;
                    }
                    index++;
                }
            }
            leftSortBorder = lastLeftExchangeIndex;
            rightSortBorder = lastRightExchangeIndex;
            System.out.println("第" + (i + 1) + "次比較後" + "--->" + Arrays.toString(origin) + ",isSorted--->" + isSorted);
            if (isSorted) {
                break;
            }
        }
        System.out.println("index--->" + index);
        System.out.println("sortedArray--->" + Arrays.toString(origin));
        return origin;
    }

執行結果如下:

五、總結

時間複雜度

同氣泡排序,假設原始陣列長度為 n,則外迴圈 n 次,每次遍歷巢狀一個內迴圈,所以時間複雜度為 O(n²)。

空間複雜度

同氣泡排序,空間複雜度為 O(1)。

優點

1.在某些特定情況下,雞尾酒排序相較於氣泡排序可以減少大量比較輪數,算是氣泡排序的一種優化。

缺點

1.程式碼量相較於氣泡排序增加了幾乎一倍。