冒泡、選擇、插入排序是演算法入門必修課,雖時間複雜度均為 O(n²),但理解其機制是掌握快排、歸並、堆排等進階算法的基石。本文提供標準 C 實現、步驟圖解、優化技巧與適用場景分析。
相鄰元素兩兩比較,逆序則交換。每輪將當前最大元素移至未排序區末尾。
初始: 4 9 10 3 2 14 11 5
第1輪: 9 10 4 3 14 11 5 2 (7次比較, 14冒泡到最前)
第2輪: 10 9 4 14 11 5 3 2 (6次比較, 11冒泡到第2)
...
最終: 14 11 10 9 5 4 3 2
void bubble_sort(int a[], int n) {
for (int i = 0; i < n - 1; ++i) { // n-1 輪
bool swapped = false;
for (int j = 0; j < n - 1 - i; ++j) { // 每輪比較次數遞減
if (a[j] < a[j + 1]) { // 降序: < ; 升序: >
int tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
swapped = true;
}
}
if (!swapped) break; // 優化: 本輪無交換已有序
}
}
n-1-i)。swapped 標誌,最好情況 O(n) (已有序)。在未排序區找到最大值,與未排序區首位交換。每輪確定一個元素最終位置。
初始: 4 9 10 3 2 14 11 5
第1輪: 14 9 10 3 2 4 11 5 (7次比較, 14與首位4交換)
第2輪: 14 11 10 3 2 4 9 5 (6次比較, 11與第2位9交換)
...
最終: 14 11 10 9 5 4 3 2
void selection_sort(int a[], int n) {
for (int i = 0; i < n - 1; ++i) {
int max_idx = i;
for (int j = i + 1; j < n; ++j) {
if (a[j] > a[max_idx]) max_idx = j; // 降序找最大
}
if (max_idx != i) {
int tmp = a[i];
a[i] = a[max_idx];
a[max_idx] = tmp;
}
}
}
n(n-1)/2,無最好情況優化。維護前 i 個元素有序,將第 i+1 個元素向前比較移動,插入正確位置。類似整理撲克牌。
有序區: 3 5 6 8 15 17 20 21 45 50
插入 25:
比較 50>25 右移, 45>25 右移, 21<25 停止
結果: 3 5 6 8 15 17 20 21 25 45 50
void insertion_sort(int a[], int n) {
for (int i = 1; i < n; ++i) {
int key = a[i];
int j = i - 1;
while (j >= 0 && a[j] > key) { // 降序: > ; 升序: <
a[j + 1] = a[j];
--j;
}
a[j + 1] = key;
}
}
a[j] > key 不含等號)。| 指標 | 冒泡排序 | 選擇排序 | 插入排序 |
|---|---|---|---|
| 平均時間 | O(n²) | O(n²) | O(n²) |
| 最好時間 | O(n) (優化後) | O(n²) | O(n) |
| 最壞時間 | O(n²) | O(n²) | O(n²) |
| 空間複雜度 | O(1) | O(1) | O(1) |
| 穩定性 | 穩定 | 不穩定 | 穩定 |
| 交換/移動次數 | 多 (O(n²)) | 少 (O(n)) | 中 (O(n²) 移動) |
| 適合場景 | 教學、極小數據 | 寫入開銷大、小數據 | 近乎有序、小數據、在線排序 |