快速排序作為隨機演算法的一種,不能通過常規方法來計算時間複雜度
wiki上有三種快排平均時間複雜度的分析,本文記錄了一種推導方法。
先放快速排序的虛擬碼,便於回顧、參考
quicksort(int L, int R, int array[]) {
if (L >= R) {
return;
}
int pivot = RANDOM(L, R);
int l = L, r = R;
int support_array[array.length()]
for (i = L -> R) {
if (i == pivot) {
return;
}
else if (array[i] <= array[pivot]){
support_array[l++] = array[i];
}
else {
support_array[r--] = array[i];
}
}
support_array[l] = array[pivot];
array <- support_array;
quicksort(L, l-1, array);
quicksort(l+1, R, array);
}
n為序列長度,對於長度為n的序列,我們總共需要呼叫n次quicksort函式,我們將序列中元素與pivot的比較操作(程式碼8-18行,以下簡稱為“比較”)提出來總體考慮,每呼叫一次函式,除開比較操作,時間複雜度均為O(1),設x為n次呼叫函式總共的比較次數,快排的時間複雜度T(n) = O(n+x)
以下為x的計算過程
設ei為原序列中第i小的數,ej為第j小的數, j > i。在對原序列完整排序的整個過程中,每一個位置都會被選作為pivot一次。ei與ej會被比較,當且僅當在ei, ei+1, ei+2 , ... , ej-1, ej 這個子序列中(按照假設,此為非降序序列),ei與ej其中一個最先在這個子序列中被選為pivot ,否則一個大小介於他們中間的數被選為pivot,在一輪比較過後,ei和ej就會被分在兩個子序列中,沒有被比較且以後也不會被比較。當我們使用的生成隨機數演算法能保證每個數被選中為pivot的概率相等時,P(ei與ej被比較) = 2 / ( j - i + 1 )。設Y為ei與ej比較的次數,Y = 0 或 1, Y的期望計算如下
\[P(Y=1) = P(e_i與e_j被比較) = 2 / ( j - i + 1 )
\]
\[E(Y) = P(Y=1) * 1 = 2 / ( j - i + 1 )
\]
而在序列中,任意兩項比較次數的期望均是 2 / ( j - i + 1 )
x是總共比較次數,則x的期望的表示式為
\[E(x) = \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}2/(j-i+1)
\]
後半部分的求和是調和級數(harmonic series), 調和級數求和公式如下
\[1+1/2+1/3+...+1/n = ln(n+1) + γ
\]
用於計算E(x)
\[\sum_{j=i+1}^{n}2/(j-i+1) = 2 * [ln(n-i+1)-1+γ] = O(logn)
\]
\[E(x) = \sum_{i=1}^{n-1}O(logn) = O(nlogn)
\]
\[T(n) = O(n+x) = O(n + nlogn) = O(nlogn)
\]
到此,快速排序的平均時間複雜度O(nlogn)也就推導完成了。