1:快速排序
快速排序的最壞情況時間複雜度為
θ(n^2
)。雖然最壞情況時間複雜度很差,但是快速排序通常是實際排序應用中最好的選擇,因為它的平均效能很好。它的期望執行時間複雜度為
θ(n lg n)
,而且θ
(n lg n)
中蘊含的常數因子非常小,而且它還是原址排序的。
2:基本思想
快速排序採用分治法進行排序,首先在陣列中選擇乙個元素p,根據元素p將陣列劃分為兩個子陣列,在元素
p左側的子陣列的所有元素都小於或等於該元素
p,右側的子陣列的所有元素都大於元素p。
下面是對乙個典型子陣列a[p...r]排序的分治過程的三個步驟:
a、分解:陣列a[p..r]被劃分為兩個子陣列a[p..q-1]和a[q+1..r]使得a[p..q-1]中的每個元素都小於等於a(q),而且,元素a(q)小於等於a[q+1..r]中的元素。下標q也在這個劃分過程中進行計算。
b、解決:通過遞迴呼叫快速排序,對子陣列a[p..q-1]和a[q+1...r]排序。
c、合併:快速排序對子陣列採用就地排序,將兩個子陣列的合併並不需要操作。
該演算法的偽**如下:
quicksort( a, p, r )
if p < r
then q =partition( a, p, r );
quicksort( a,p, q - 1);
qucksort( a, q+ 1, r );
該演算法的關鍵部分就是partition,partition不僅將陣列分為兩個子陣列,而且返回選擇key元素的位置。
partition子程式的偽**如下,該過程的時間複雜度為θ
(n):
partition( a, p, r )
x = a[r];//選取最後乙個元素為比較值(主元,pivot element)
i = p - 1;
//i是分界點,i之前(包括i)的元素都小於x,i之後,j之前的元素都大於x
for( j = p; j <= r - 1;j ++ )
if ( a[j] <= x )
exchange( a[i+1] ,a[r] );
return i + 1;
在partition中,首先選擇乙個主元,根據該主元對陣列進行劃分,劃分為
4部分,如下圖所示:
對照**中的部分,這
4部分包括:
a:範圍pk
i中,a[k]x;
b:範圍
i+1k
j-1中,
a[k];c
:範圍j
kr-1
中,陣列元素未劃分,最終都要劃分到上面倆範圍之一;d:
k=r,則
a[k]x;
3:快速排序的效能
快速排序的執行時間依賴於劃分是否平衡,如果劃分平衡,那麼快速排序演算法效能與歸併排序一樣,如果劃分不平衡,那麼快速排序的效能就接近於插入排序了。
最壞情況下,每次劃分的兩個子問題都分別包含了n-1個元素和0個元素。劃分的時間代價為o(n),因為對乙個大小為0的陣列進行遞迴呼叫後,返回了t(n)=o(1),故演算法的執行時間可遞迴的表示為:
t(n) = t(n-1) + t(0) + o(n)= t(n-1) + o(n)
該遞迴式的解為:
t(n) =
θ(n^2
)。因此,最壞情況下,也就是陣列中元素已經排好序的時候,快速排序的時間複雜度為θ(n^2
),而在同樣的情況下,插入排序的時間複雜度為o(n)。
最好的情況,每次劃分都是平均的劃分為n/2個元素子陣列,此時遞迴式為:t(n) = 2t(n/2) + o(n)
該遞迴式可得t(n) = o(nlgn)。
快速排序的平均執行時間更接近於其最好情況,而非最壞情況,事實上,任何一種常數比例的劃分都會產生深度為
θ(nlg n)的遞迴樹,其中每一層的代價都是o(n),因此,只要劃分是常數比例的,演算法的執行時間總是o(n lgn)。
4:快速排序的隨機化版本
當輸入的資料是隨機排列的時候,快速排序的時間複雜度是o(n lgn)。但是在實際中,輸入並不總是隨機的,因此需要在演算法中引入隨機性,可以對輸入進行重新排列是演算法實現隨機化, 也可以進行隨機抽樣,隨機抽樣是從陣列
a[p…r]
中隨機選擇乙個元素作為主元,演算法如下:
randomized-partition(a, p, r)
i = random(p,r)
exchange a[r] with a[i]
return partition(a, p, r)
randomized-quicksort(a, p, r)
if p < r
q = randomized -partition(a, p, r );
quicksort( a, p, q -1);
qucksort( a, q + 1, r);
5:尾遞迴
普通的快速排序需要兩次的遞迴呼叫,分別針對左子陣列和右子陣列,可以使用尾遞迴技術消除quicksort中第二個遞迴呼叫,也就是用迴圈代替它,好的編譯器都具有這種功能:
tail-recursive-quicksort(a, p, r)
while p < r
q = partition(a, p, r)
tail-recursive-quicksort(a,p, q-1)
p = q+1
6:完整**如下:
int partition(int *set, int begin, int end)
}exchange(set+i+1, set+end);
return i+1;
}void quicksort(int *set, int begin, int end)
}
演算法導論筆記 07快速排序
1 快速排序 快速排序的最壞情況時間複雜度為 n 2 雖然最壞情況時間複雜度很差,但是快速排序通常是實際排序應用中最好的選擇,因為它的平均效能很好。它的期望執行時間複雜度為 n lg n 而且 n lg n 中蘊含的常數因子非常小,而且它還是原址排序的。2 基本思想 快速排序採用分治法進行排序,首先...
快速排序 演算法導論
對於包含n個數的輸入陣列來說,快速排序是一種最壞情況時間複雜度為o n 的排序演算法。雖然最壞情況時間的複雜度很差,但是快速排序通常是實際排序應用中最好的選擇,因為它的平均效能非常好 它的期望時間複雜度是o nlgn 而且o nlgn 中隱含的常數因子非常小,另外,它還能夠進行原址排序,甚至在虛存環...
演算法導論 快速排序
既然敢叫 快速排序 必然有其過人之處。事實上,它確實是最快的通用內部排序演算法。它由hoare於1962年提出,相對歸併排序來說不僅速度快,並且不需要輔助空間。對於包含n個數的輸入陣列來說,快速排序是一種最壞情況時間複雜度為o n 2 的排序演算法。雖然最壞情況時間複雜度差,但是快速排序通常是實際排...