快速排序是一種高效的排序算法,它基於分治(Divide and Conquer)的思想,通過選擇一個“基準元素”,將數組分成兩部分,一部分所有元素都比基準小,另一部分所有元素都比基準大,然後遞歸地對這兩部分進行排序。這種方法能快速處理大規模數據,平均時間複雜度爲 O(n log n),是實際應用中最常用的排序算法之一。

快速排序的基本步驟

以數組 [6, 3, 8, 5, 2, 7] 爲例,我們來一步步演示快速排序的過程:

  1. 選擇基準元素(Pivot):這裏選擇數組最右邊的元素 7 作爲基準。
  2. 分區(Partition):遍歷數組,將小於基準的元素移到基準左側,大於基準的元素移到右側。分區後數組變爲 [6, 3, 5, 2, 7, 8],基準 7 最終位於位置 4(索引從 0 開始)。
  3. 遞歸排序:此時,基準左側的子數組 [6, 3, 5, 2] 和右側的子數組 [8](長度爲 1,無需排序)需要分別遞歸排序。
  4. 處理左側子數組:對 [6, 3, 5, 2] 重複上述步驟,選擇最右邊元素 2 作爲基準,分區後得到 [3, 5, 2, 6],基準 2 位於位置 0,左側子數組爲空,右側子數組 [3, 5, 6] 繼續遞歸排序。
  5. 最終結果:經過多次遞歸後,數組將完全有序:[2, 3, 5, 6, 7, 8]

分區函數的核心邏輯

分區是快速排序的關鍵步驟,其目標是將數組分爲“小於基準”和“大於基準”兩部分,並返回基準元素的最終位置。以選擇最右側元素爲基準爲例,分區過程如下:

  1. 定義變量 pivot = arr[right](基準元素)。
  2. 定義指針 i 指向“小於基準區域”的末尾(初始爲 left - 1)。
  3. 遍歷數組(從 leftright - 1):
    - 若當前元素 arr[j] <= pivot,則將其加入“小於基準區域”,即 i++ 後交換 arr[i]arr[j]
  4. 遍歷結束後,將基準元素 pivot 交換到 i + 1 的位置(“小於基準區域”的末尾 + 1),此時基準元素左側均小於它,右側均大於它。

Java 代碼實現

下面是使用 Java 實現快速排序的完整代碼,包含分區函數和遞歸排序邏輯:

public class QuickSort {

    // 快速排序主方法:遞歸排序數組的 [left, right] 區間
    public static void quickSort(int[] arr, int left, int right) {
        // 遞歸終止條件:區間長度小於等於1時無需排序
        if (left < right) {
            // 分區操作,返回基準元素的最終位置
            int pivotIndex = partition(arr, left, right);
            // 遞歸排序基準左側子數組
            quickSort(arr, left, pivotIndex - 1);
            // 遞歸排序基準右側子數組
            quickSort(arr, pivotIndex + 1, right);
        }
    }

    // 分區函數:選擇最右側元素爲基準,返回基準的最終位置
    private static int partition(int[] arr, int left, int right) {
        int pivot = arr[right]; // 選擇最右側元素作爲基準
        int i = left - 1; // i 指向“小於基準區域”的末尾(初始爲空)

        // 遍歷數組,將小於等於基準的元素移到左側
        for (int j = left; j < right; j++) {
            if (arr[j] <= pivot) {
                i++; // 擴展“小於基準區域”
                // 交換 arr[i] 和 arr[j],將當前元素加入“小於基準區域”
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        // 將基準元素交換到最終位置(i+1)
        int temp = arr[i + 1];
        arr[i + 1] = arr[right];
        arr[right] = temp;

        // 返回基準元素的索引
        return i + 1;
    }

    // 測試方法:驗證快速排序的正確性
    public static void main(String[] args) {
        int[] arr = {6, 3, 8, 5, 2, 7};
        System.out.println("排序前數組:");
        for (int num : arr) {
            System.out.print(num + " ");
        }

        quickSort(arr, 0, arr.length - 1);

        System.out.println("\n排序後數組:");
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }
}

代碼運行結果

運行上述代碼,輸出如下:

排序前數組:
6 3 8 5 2 7 
排序後數組:
2 3 5 6 7 8 

時間複雜度與空間複雜度

  • 時間複雜度:平均情況下爲 O(n log n)(每次分區操作將數組分爲大致相等的兩部分,遞歸深度爲 log n);最壞情況下(如數組已排序或逆序)爲 O(n²)(每次分區僅將數組分爲 1 和 n-1 兩部分,遞歸深度爲 n)。
  • 空間複雜度:主要來自遞歸調用棧,平均爲 O(log n),最壞爲 O(n)。

總結

快速排序通過分治思想高效排序數組,核心在於分區操作和遞歸處理。其優點是平均效率高,適合大規模數據;缺點是不穩定排序(相等元素的相對順序可能改變),且最壞情況性能較差。掌握快速排序不僅能理解分治算法,也能爲後續學習更復雜的排序算法打下基礎。

小夜