1. 什麼是快速排序?基礎概念與概要
快速排序是一種排序演算法,廣泛應用於C語言及許多其他程式語言中,以高效率地對資料進行排序。此演算法由C. A. R. Hoare發明,最大的特色是執行速度極快。
快速排序的基本思路
快速排序會利用稱為樞紐(Pivot)的基準值將資料分割,並以遞迴方式對資料進行排序。透過這種分割治療法(Divide and Conquer),最終可以讓所有元素達到排序狀態。
- 樞紐(Pivot):任意選定的值,根據此值將資料分為兩組。
- 分割治療法:將問題拆解成較小的子問題,各自解決後,再整合出全體問題的答案。
相較於其他排序演算法(如泡沫排序、插入排序),快速排序在處理大型資料集時具有極高的效能優勢。
2. 快速排序演算法說明
接下來,將詳細介紹快速排序的演算法運作機制。
樞紐的選擇
快速排序的第一步,是從陣列中選出樞紐。樞紐的選擇會影響演算法執行效率,選取不同的值會帶來不同的效能結果。
- 範例:可選擇陣列的第一個元素、最後一個元素,或中間的元素作為樞紐。
遞迴分割處理
選好樞紐後,以此為基準把陣列分為兩部分。小於樞紐的值移到一邊,大於的移到另一邊。完成後,對剩餘的部分再次以相同方式遞迴處理。
- 步驟1:將比樞紐小的元素移到左側,比樞紐大的元素移到右側。
- 步驟2:對每個分割後的子陣列再次進行快速排序。
這個遞迴分割的過程持續下去,直到整個陣列都排序完成。
3. 用C語言實現快速排序
下面說明如何以C語言實際實現快速排序。以下是基本的快速排序程式碼範例:
#include <stdio.h>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 選擇最後一個元素作為樞紐
int i = (low - 1); // 小於樞紐的元素索引
for (int j = low; j <= high - 1; j++) {
if (arr[j] <= pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
// 對分割後的子陣列遞迴進行快速排序
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main() {
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, 0, n - 1);
printf("Sorted array:n");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("n"); // 輸出換行,讓結果更易讀
return 0;
}
這段程式碼中,swap函式用於交換兩個元素,partition函式以樞紐為基準分割陣列,然後由quickSort函式進行遞迴排序。

4. 快速排序的效能與最佳化
快速排序的效能相較於其他排序演算法非常優異,但在最糟情況下運算時間也可能惡化。本節將說明效能細節與最佳化方法。
計算複雜度與最差情境
快速排序的平均複雜度為O(n log n),但在排序過或重複值過多的陣列中,最差情境會降至O(n^2),這時遞迴深度變大、效率降低。
最佳化技巧
- 優化樞紐選擇:不要只用第一個或最後一個元素,選擇中間或隨機的元素可讓分割更平均。
- 控制遞迴呼叫深度:可考慮改用非遞迴方式實現,降低堆疊溢位的風險。
5. 快速排序與其他排序法的比較
快速排序非常高效,但也有其他常見的排序演算法。本節將比較各排序法的特點與優缺點。
快速排序 vs. 合併排序
- 演算法機制:
快速排序與合併排序同樣採用分割治療法,但分割和合併的方式不同。快速排序著重在分割,每個子陣列各自排序;合併排序著重於合併,將排序後的子陣列組合成最終結果。 - 效能比較:
兩者的平均時間複雜度皆為O(n log n),但快速排序最差情境為O(n^2),合併排序即使在最差情況下也可保持O(n log n),效能較穩定。 - 優缺點:
快速排序通常記憶體效率更佳(不需額外空間),適合大數據,但要注意最差情境。合併排序是穩定排序,即便資料近乎排序也可保證效能。
快速排序 vs. 堆積排序
- 演算法機制:
快速排序採用遞迴分割,堆積排序則是將資料結構轉成堆積(Heap),依序取出最大(最小)元素進行排序。 - 效能比較:
堆積排序與快速排序平均皆為O(n log n),但通常快速排序實際執行較快,尤其資料較亂時更明顯。 - 優缺點:
快速排序一般比堆積排序快,但堆積排序即使在最壞情境下也能保證O(n log n),因此在極端情況下較安全。
快速排序 vs. 氣泡排序
- 演算法機制:
氣泡排序會重複比較相鄰元素並交換,方式非常簡單但效率很低,與快速排序完全不同。 - 效能比較:
氣泡排序時間複雜度為O(n^2),比快速排序低效很多。僅適合元素極少的場合。 - 優缺點:
氣泡排序容易理解與實作,但效能差,實務上極少使用。
6. 快速排序常見錯誤與除錯方法
實作快速排序或使用qsort()
時,常會遇到一些錯誤。這裡整理幾個常見錯誤及其對策。
1. 堆疊溢位(Stack Overflow)
快速排序屬於遞迴演算法,當遞迴層數過多時可能會發生堆疊溢位。避免方式包括限制遞迴深度,或考慮改為非遞迴實作。
- 解決方式:將遞迴處理改用迴圈,可有效降低堆疊溢位的風險。
2. 無窮迴圈
若遞迴處理或樞紐選擇出錯,可能會發生無窮迴圈。常見於樞紐選擇條件或結束條件未正確設定。
- 解決方式:檢查樞紐選擇與排序終止條件,確保能正確結束遞迴。
3. 記憶體存取違規
以指標操作陣列元素時,若超出陣列範圍會出現記憶體存取違規錯誤。
- 解決方式:確認未超出陣列範圍,且遞迴處理正確進行。
7. 總結與後續應用
快速排序是C語言中效率最高的排序演算法之一,特別適合大數據集。運用樞紐選擇與分割治療法,可遞迴完成高效排序。此外,標準函式庫的qsort()
也可輕鬆完成強大排序功能。
實務應用時,建議依資料特性調整樞紐選擇,以提升效能。若遇到錯誤,請檢查遞迴與記憶體管理。希望本篇能幫助你從基礎到實作全面理解快速排序,靈活應用於實際開發中。