20. 排序--快速排序

快速排序

算法概述

從數組中選出一個數作爲主元,然後把數組一分爲二,左邊是小於主元的,右邊是大於主元的。重複這個過程,直到劃分的子集長度爲1

僞碼描述

void Quick_Sort(ElementType[] A, int N) {
    pivot = 從數組A中選出一個主元;
    將 S = {A[] \ pivot}分成2個獨立子集:
        A1 = {小於等於pivot} 和
        A2 = {大於等於pivot};

    A[] = Quick_Sort(A1, N1) + pivot + Quick_Sort(A2, N2);
}

快速排序算法的最好情況:每次都劃分爲相等的兩部分,因此時間複雜度爲T(N)=O(NlogN)

選主元

  • pivot每次取第一個
  • 隨機取pivot:rand()函數消耗大
  • 取頭、中、尾的中位數:比較常用的一種做法

取中位數的實現

// 返回主元的下標
int Median3(ElementType[] A, int Left, int Right) {
    int Center = (Left + Right) / 2;
    if (A[Left] > A[Center])
        Swap(&A[Left], &A[Center]);
    if (A[Left] > A[Right])
        Swap(&A[Left], &A[Right]);
    if (A[Center] > A[Right])
        Swap(&A[Center], &A[Right]);
    // 以上三次交換實現 A[Left] <= A[Center] <= A[Right]

    Swap(&A[Center], &A[Right - 1]);    // 將主元藏到右邊
    // 在後面比較過程中只需要考慮 A[Left + 1]到A[Right - 2]

    return Right - 1;
}

子集劃分

  1. 從數組左邊開始向右掃描,直到有元素比主元大,然後停下
  2. 從數組右邊開始向左掃描,直到有元素比主元小,然後停下
  3. 交換兩個元素後,重複以上步驟,直到左邊下標大於等於右邊下標
  4. 將主元置於左邊停下的位置

如果有元素正好等於pivot:

  • 停下來交換
  • 繼續掃描

假設一種極端情況,數組全部由相同元素組成。

  • 第一種方案雖然會做多次無用交換,但是最後主元的位置會在中心
  • 第二種方案雖然減少了無用交換,但是最後主元位置會在一端
  • 所以說,選擇停下來交換,保證主元的位置能靠近中心

小規模數據的處理

  • 快速排序的問題
    • 使用遞歸消耗比較大
    • 對小規模的數據(例如N不到100)可能還不如插入排序快
  • 解決方案
    • 當遞歸的數據規模充分小,則停止遞歸,直接調用簡單排序(例如插入排序)
    • 在程序中定義一個Cutoff的閥值

算法實現

void Quick_Sort(ElementType[] A, int Left, int Right) {
    if (Cutoff <= Right - Left) {
        PivotIndex = Median3(A, Left, Right);
        Pivot = A[PivotIndex];

        i = Left;
        j = Right - 1;

        while (true) {
            while (A[++i] < Pivot);
            while (A[--j] > Pivot);

            if (i < j)
                Swap(&A[i], &A[j]);
            else break;
        }

        Swap(&A[i], &A[PivotIndex]);
        Quick_Sort(A, Left, i - 1);
        Quick_Sort(A, i + 1, Right);

    } else 
        Insertion_Sort(A + Left, Right - Left + 1);
}

void Quick_Sort(ElementType[] A, int N) {
    Quick_Sort(A, 0, N - 1);
}
  • 穩定性:快速排序是不穩定
  • 平均時間複雜度:T(N)=O(NlogN)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章