基礎
看懂《算法導論》需要重溫數學知識。算法實現和推導是一個數學建模過程。
原理
對於包含 n 個數的輸入數組來說,快速排序是一種最壞情況時間複雜度爲 O() 的排序算法。雖然最壞情況的時間複雜度很差,但是快排通常是實際排序應用中最好的選擇,因爲它平均性能非常好,它的期望實際複雜度是O(),而且O()中隱含的常數因子非常小,另外它還能夠進行原址排序,甚至在虛存環境中也能很好地工作。
詳細內容請參考《算法導論》第三版,第二部分,第七章:快速排序
實現
根據數組哨兵的選擇,有兩種遞歸方式實現。調試代碼在 (github)
- 以數組末位數值爲哨兵,從左向右排序
int Partition(int array[], int start, int end) {
int low = start - 1;
int high = low + 1;
int key = array[end];
for (; high < end; high++) {
if (array[high] <= key) {
low++;
if (high > low) {
int temp = array[low];
array[low] = array[high];
array[high] = temp;
}
}
}
// 如果是有序數組,會出現左邊都是最小的情況,要置換 partition 需要判斷數據。
int partition = low + 1;
if (array[partition] > key) {
int temp = array[partition];
array[partition] = array[end];
array[end] = temp;
}
return partition;
}
void qsort_end(int array[], int start, int end) {
if (start < 0 || end <=0 || start >= end) {
return;
}
int partition = Partition(array, start, end);
if (partition >= 0) {
qsort_end(array, start, partition - 1);
qsort_end(array, partition + 1, end);
}
}
- 以數組中間數值爲哨兵,從兩端向中間排序
void qsort_mid(int array[], int start, int end) {
if (start >= end) {
return;
}
int high = end;
int low = start;
int key = array[(unsigned int)(start + end) / 2];
while (low < high) {
// 左邊向右查找比 key 大的
while (array[low] < key && low < end) {
low++;
}
// 右邊向左查找比 key 小的
while (array[high] > key && high > start) {
high--;
}
if (low <= high) {
int temp = array[low];
array[low] = array[high];
array[high] = temp;
low++;
high--;
}
}
qsort_mid(array, start, high);
qsort_mid(array, low, end);
}
時間複雜度推導
最優情況下的時間複雜度
快速排序涉及到遞歸調用, 遞歸算法的時間複雜度公式:
數組共有 個數值,最優的情況是每次取到的元素(哨兵)剛好平分整個數組。
此時的時間複雜度公式爲:
第一次遞歸:
第二次遞歸:令 ,
第三次遞歸:令
…
第 次遞歸:令
公式一直往下迭代,當最後數組不能再平分時,最後到,說明公式迭代完成(是常量)也就是:
==> ( ) ==> ( )
當 時
爲元素個數,當 時
參考
算法導論 時間複雜度分析
快速排序 及其時間複雜度和空間複雜度
算法導論------遞歸算法的時間複雜度求解
算法複雜度中的O(logN)底數是多少
Cmd Markdown 公式指導手冊