1. 程式人生 > >【演算法導論】7.快速排序

【演算法導論】7.快速排序

快速排序的平均時間複雜度為O(nlgn),最壞時間複雜度為O(n^2),最壞時間複雜度出現在待排序列完全有序的狀態,此時在使用分治法進行劃分時,兩個子序列的規模相差很大,就出現了最壞時間複雜度。快速排序由於其O(nlgn)前隱含的常數係數非常小,所以相比其它排序演算法更快。


7.1快速排序的描述

快排使用了分治思想。

分解:將待排陣列A[p..r]劃分成兩個(如果選取的劃分元素不好,會導致其中一個為空)子陣列A[p..q-1]和A[q+1..r],其中A[p..q-1]中的每個元素都小於等於A[q],A[q+1..r]中的每個元素都大於等於A[q]。計算下標q也屬於劃分過程的一部分。

解決:遞迴呼叫快排,對子陣列A[p..q-1]和A[q+1..r]進行排序。

合併:由於子陣列是原址排序,所以不需要合併。

快排的實現:

QuickSort(A,p,r)
{
    if p<r
    {
        q=Partition(A,p,r);//分解
        QuickSort(A,p,q-1);//解決:對兩個子陣列進行遞迴
        QuickSort(A,q+1,r);
    }
}

其中Partition用於對子陣列進行原址重排:在每個子陣列A[p,r]上的時間複雜度為O(n),n為子陣列的長度。

(注意這個快排和資料結構課本中,有一個頭指標和一個尾指標的快排不一樣,這裡用於標記兩個子陣列的指標,都是從下標p開始掃描陣列。這裡的終止條件是j從p掃描到r;使用頭指標和尾指標的快排的終止條件是兩個指標在陣列中間相遇。最後對主元的處理,這裡是將主元與最左的大於x的元素進行交換;另一種快排是將主元放在兩個指標相遇的位置)。

Partition(A,p,r)
{
    x=A[r];//這裡選陣列中最後一個值作為劃分主元
    i=p-1;//i為待排陣列左邊的下標值
    for j=p to r-1
    {
        if A[j]<=x//把值正確的分在x的兩邊
        {
            i++;
            exchange A[i] with A[j];
        }
    }
    exchange A[i+1] with A[r];
    return i+1;
}

7.2快速排序的效能

快排的執行時間依賴於劃分是否平衡(分治法的時間複雜度),平衡依賴於用於劃分的元素。如果劃分的平衡,快排的演算法效能與歸併排序一樣,如果不平衡,退化成插入排序。

1.最壞情況的劃分:兩個子問題分別包含n-1個元素和0個元素。並且每次遞迴呼叫都出現這種不平衡劃分。此時快排的時間複雜度為O(n^2),插入排序的時間複雜度為O(n)。

2.最好情況的劃分:Partition得到的兩個子問題的規模都不大於n/2. 此時時間複雜度為O(nlgn).

3.平衡的劃分:快排的平均執行時間更接近於其最好情況。只要劃分是常數比例,演算法的執行時間總是O(nlgn).

4.對於平均情況的直接觀察:快排的行為依賴於輸入陣列中元素的值的相對順序,而不是某些特定值本身。當好和差的劃分交替出現時,快排的時間複雜度與全是好的劃分一樣,為O(nlgn)。(影響前面的係數,不影響問題的規模)。


7.3快排的隨機化版本

由於實際問題中,不會像假設中“輸入資料的所有排列都是等概率的”。所以可以通過在演算法中引入隨機性,從而使演算法對於所有的輸入都有較好的期望效能。

採用隨機抽樣的隨機化技術,從子陣列A[p..r]中隨機選擇一個元素作為主元。實現方法:首先將A[r]與從A[p..r]中隨機選出的一個元素進行交換。通過對序列p...r的隨機抽樣,可以保證主元x=A[r]是等概率地從子陣列的r-p+1個元素中選取的。由於是隨機選取的主元,我們期望在平均情況下,對輸入陣列的劃分是較為均衡的。

在新的劃分中,需要在真正進行劃分前進行一次交換:

Randomized-QuickSort(A,p,r)
{
    i=Random(p, r);//從p...r這些下標中隨機選取一個
    exchange A[i] with A[r];
    return Partition(A,p,r);
}

之後進行排序:

Randomized-QuickSort(A,p,r)
{
    if p<r
    {
        q=Randomized-Partition(A,p,r);//和普通快排的區別就在於這個A[r]和前面不一樣
        Randomized-QuickSort(A,p,q-1);
        Randomized-QuickSort(A,q+2,r);
    }
}