排序算法之4:快速排序 QuickSort

快速排序(英語:Quicksort),又稱劃分交換排序(partition-exchange sort),一種[排序算法],最早由[東尼 · 霍爾]提出。在平均狀況下,排序n個項目要[Ο](n log n) 次比較。在最壞狀況下則需要Ο(n^2) 次比較,但這種狀況并不常見。事實上,快速排序通常明顯比其他Ο(n log n) 算法更快,因為它的內部循環(huán)(inner loop)可以在大部分的架構上很有效率地被實現出來。

快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分為兩個子序列(sub-lists)。
步驟為:

  1. 從數列中挑出一個元素,稱為 "基準"(pivot),
  2. 重新排序數列,所有比基準值小的元素擺放在基準前面,所有比基準值大的元素擺在基準后面(相同的數可以到任一邊)。在這個分區(qū)結束之后,該基準就處于數列的中間位置。這個稱為分區(qū)(partition)操作。
  3. 遞歸地(recursively)把小于基準值元素的子數列和大于基準值元素的子數列排序。

遞歸到最底部時,數列的大小是零或一,也就是已經排序好了。這個算法一定會結束,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最后的位置去。

public class QuickSort {
    public static void sort(int[] arr) {
        if (arr == null || arr.length == 0) {
            return;
        }
        quickSort(arr, 0, arr.length - 1);
    }

    /**
     * 遞歸劃分子序列
     *
     * @param arr
     * @param left
     * @param right
     */
    public static void quickSort(int[] arr, int left, int right) {

        System.out.println("quickSort:" + print(arr));

        if (left >= right) {
            return;
        }
        int pivotPos = partition(arr, left, right);
        quickSort(arr, left, pivotPos - 1);
        quickSort(arr, pivotPos + 1, right);
    }
    
    /**
     * 稍優(yōu)的劃分邏輯
     * 一次劃分流程
     * 
     * 按照把左邊第一個數字作為基準數的話,邏輯如下:
     * 1. 右指針從右往左找到比基準數小的數字,找到時指針停止移動,且給左指針數字賦值為右指針對應的數字
     * 2. 左指針從左往右找到比基準數大的數字,找到時指針停止移動,且給右指針數字賦值為左指針對應的數字
     * 3. 交換相遇時的數字和基準數
     * 4. 此時基準數左邊都是比基準數小的數字,基準數右邊都是比基準數大的數字
     * 5. 此時一輪劃分執(zhí)行完畢
     *
     * @param arr
     * @param left 左指針
     * @param right 右指針
     * @return
     */
    public static int partition(int[] arr, int left, int right) {
        int pivotKey = arr[left];

        while (left < right) {
            while (left < right && arr[right] >= pivotKey) {
                right--;
            }
            arr[left] = arr[right]; //把小的數字移動到左邊
            System.out.println(print(arr));
            
            while (left < right && arr[left] <= pivotKey) {
                left++;
            }
            arr[right] = arr[left]; //把大的移動到右邊
            System.out.println(print(arr));
        }
        arr[left] = pivotKey; //最后把pivot賦值到中間
        System.out.println(print(arr));
        
        return left;
    }

    /**
     * 代碼中基準數已經在 pivotKey 中保存了,所以不需要每次交換都設置一個 temp 變量,
     * 在交換左右指針的時候只需要先后覆蓋就可以了。
     * 這樣既能減少空間的使用還能降低賦值運算的次數
     * 
     * 一次劃分流程
     *
     * 按照把左邊第一個數字作為基準數的話,邏輯如下:
     * 1. 右指針從右往左找到比基準數小的數字,找到時指針停止移動
     * 2. 左指針從左往右找到比基準數大的數字,找到時指針停止移動
     * 3. 交換這兩個數字
     * 4. 重復步驟1和步驟2,如果兩者相遇時,則停止移動
     * 5. 交換相遇時的數字和基準數
     * 6. 此時基準數左邊都是比基準數小的數字,基準數右邊都是比基準數大的數字
     * 7. 此時一輪劃分執(zhí)行完畢
     *
     * @param arr
     * @param left 左指針
     * @param right 右指針
     * @return
     */
    public static int partitionOld(int[] arr, int left, int right) {
        int pivotKey = arr[left];
        int initLeft = left;
        
        while (left < right) {
            while (left < right && arr[right] >= pivotKey) {
                right--;
            }

            while (left < right && arr[left] <= pivotKey) {
                left++;
            }
            
            swap(arr, left, right);
            System.out.println(print(arr));
        }

        swap(arr, initLeft, left);
        System.out.println(print(arr));
        return left;
    }

    public static void swap(int[] arr, int left, int right) {
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 筆者在學習數據結構與算法時,嘗試著將排序算法以動畫的形式呈現出來更加方便理解記憶,本文配合Demo 在Object...
    五分鐘學算法閱讀 1,738評論 9 51
  • 作者:快課網——Jay13原文地址:http://www.cricode.com/3212.html 排序算法可以...
    IT程序獅閱讀 3,840評論 2 78
  • 今天我們來總結一下經典常用的排序算法。 排序算法可以分為內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而...
    Tangmi_Up閱讀 1,821評論 1 15
  • 慣例在異國一邊玩一邊接咨詢預約。然后問自己,這和在上海有什么不同?嗯,似乎在上海工作有種莫名的焦慮,覺得還不夠好還...
    莎珈閱讀 590評論 0 2
  • 春節(jié)期間陪先生回了趟老家,主要是因為臨時收到通知,先生的侄女(堂哥的女兒)要結婚了,要回家喝喜酒。剛剛接到消息的時...
    胭脂在線閱讀 312評論 0 0

友情鏈接更多精彩內容