一、介紹及原理
簡單來說,快速排序就是每次選擇一個基准。在遍歷整個數組的過程中,將比基准小的數放到左側,比基准大的數放到右側。這樣在一次循環過后,雖然整體依然無序,但是算法將數列分為兩部分:左側部分小於基准數而右側部分大於基准數。之后利用分治思想分別將左側部分與右側部分進行快排,最終則可以得到一個完全有序的數組。
二、代碼實現
public static void QuickSort(int[] arr , int left , int right) {
// 遞歸的出口必須仔細考慮清楚,否則就會陷入無窮循環從而使棧溢出
if (left >= right) {
return;
}
int pivot = arr[left];
int i = left;
int j = right;
while (i < j) {
// 這里如果pivot 選在左側,就要先從右側開始遍歷,反之則先從左側開始
while (arr[j] > pivot && i < j) {
j--;
}
// 找到比基准小的數換到左側去
arr[i] = arr[j];
while (arr[i] < pivot && i < j) {
i++;
}
// 找到比基准大的數換到右側去
arr[j] = arr[i];
}
// 最后將基准放到中間位置
arr[i] = pivot;
// 遞歸快排左側數列
QuickSort(arr,left,i - 1);
// 遞歸遍歷右側數列
QuickSort(arr, i + 1, right);
}
三、時間復雜度
在算法中有一個主定理可用來考慮算法的時間復雜度:
\[T(n) = aT(\frac{n}{b}) + O(n^{d}),(a>1,b>1,d>0) \]
\[if \ \ d <log_{b}^{a}:T(n) = O(n^{log_{b}^{a}}) \\ if \ \ d =log_{b}^{a}:T(n) = O(n^{log_{b}^{a}}log_{n}) \\ if \ \ d >log_{b}^{a}:T(n) = O(n^{d}) \]
在快速排序這個問題中:
\[T(n) = 2T(\frac{n}{2}) + O(n) \ = 4T(\frac{n}{4}) + O(n) + O(n) \]
仔細考慮排序過程,第一次將數組整個掃描了一遍,時間復雜度為O(n),掃描之后將數組分成了兩個子問題:之后兩個問題分為四個子問題,時間復雜度又用了O(n),正好符合上式。
其中,O(n) 是每一次分區所用的時間復雜度,將參數帶入可知,快速排序的時間復雜度為O(nLogn)。
其實不利用公式來考慮時間復雜度的話:每次用O(n) 的時間復雜度將問題為了兩個子問題。假設m 次過后子問題划分為1 ,那么有
\[n/2/2/.../2 = \frac{n}{2^{m}} = 1 \]
所以經過了m次迭代后,問題歸一。每次的時間復雜度為O(n) = cn,那么可得快速排序的時間復雜度為:
\[cmn = clog_{2}{n}n = O(nlogn) \]