1. 程式人生 > 其它 >快速排序平均時間複雜度O(nlogn)的推導

快速排序平均時間複雜度O(nlogn)的推導

快速排序作為隨機演算法的一種,不能通過常規方法來計算時間複雜度,本文記錄了一種推導方法

快速排序作為隨機演算法的一種,不能通過常規方法來計算時間複雜度

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)也就推導完成了。