| 算法 | 時間複雜度 | 空間 | 穩定性 | 適合場景 |
|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(1) | 穩定 | 教學、極小數據、近乎有序 |
| 選擇排序 | O(n²) | O(1) | 不穩定 | 寫入開銷大(交換少)、內存受限 |
| 插入排序 | O(n²) / O(n) 最好 | O(1) | 穩定 | 小數據、近乎有序、在線數據 |
| 歸併排序 | O(n log n) | O(n) | 穩定 | 大數據、外部排序、鏈表 |
| 快速排序 | O(n log n) 平均 | O(log n) | 不穩定 | 通用內部排序、標準庫 `qsort` |
| 堆排序 | O(n log n) | O(1) | 不穩定 | 實時系統、嵌入式、保證最壞情況 |
void bubble_sort(int *a, int n) {
for (int i = 0; i < n - 1; ++i) {
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; // 優化:本輪無交換已有序
}
}
優化點:`swapped` 標誌提前終止;雙向冒泡(雞尾酒排序)減少來回。
void selection_sort(int *a, int n) {
for (int i = 0; i < n - 1; ++i) {
int min_idx = i;
for (int j = i + 1; j < n; ++j)
if (a[j] < a[min_idx]) min_idx = j;
if (min_idx != i) {
int tmp = a[i]; a[i] = a[min_idx]; a[min_idx] = tmp;
}
}
}
特性:交換次數固定 n-1 次(最少),但比較次數固定 n(n-1)/2,不適應數據狀態。
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;
}
}
優勢:
void shell_sort(int *a, int n) {
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; ++i) {
int key = a[i];
int j = i;
while (j >= gap && a[j - gap] > key) {
a[j] = a[j - gap];
j -= gap;
}
a[j] = key;
}
}
}
時間複雜度視間隔序列而定(如 Hibbard O(n^{3/2})、Sedgewick O(n^{4/3})),工程常用。
int linear_search(const int *a, int n, int key) {
for (int i = 0; i < n; ++i)
if (a[i] == key) return i;
return -1;
}
// 迭代版(推薦,無棧開銷)
int binary_search(const int *a, int n, int key) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2; // 防溢出
if (a[mid] == key) return mid;
else if (a[mid] < key) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}
// 遞歸版
int binary_search_rec(const int *a, int lo, int hi, int key) {
if (lo > hi) return -1;
int mid = lo + (hi - lo) / 2;
if (a[mid] == key) return mid;
return a[mid] < key ? binary_search_rec(a, mid + 1, hi, key)
: binary_search_rec(a, lo, mid - 1, key);
}
// 返回第一個 >= key 的位置(若全 < key 返回 n)
int lower_bound(const int *a, int n, int key) {
int lo = 0, hi = n;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < key) lo = mid + 1;
else hi = mid;
}
return lo;
}
// 返回第一個 > key 的位置
int upper_bound(const int *a, int n, int key) {
int lo = 0, hi = n;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] <= key) lo = mid + 1;
else hi = mid;
}
return lo;
}
// 統計 key 出現次數
int count_occurrences(const int *a, int n, int key) {
return upper_bound(a, n, key) - lower_bound(a, n, key);
}
#include
int cmp_int(const void *a, const void *b) {
int ia = *(const int*)a;
int ib = *(const int*)b;
return (ia > ib) - (ia < ib); // 避免溢出,返回 -1/0/1
}
int main() {
int a[] = {9, 3, 5, 1, 7};
int n = sizeof(a)/sizeof(a[0]);
qsort(a, n, sizeof(int), cmp_int); // 快速排序(實現相關)
int key = 5;
int *found = bsearch(&key, a, n, sizeof(int), cmp_int);
if (found) printf("Found at index %ld\n", found - a);
else puts("Not found");
return 0;
}
排序與查找是算法基石。插入排序以適應性強、常數小成為小規模/近乎有序首選;二分查找及其變體是有序數組查找標準解;工程中優先標準庫 `qsort/bsearch` 或 C++ STL,僅在極致性能、特殊約束(嵌入式、實時、穩定、外部排序)下手寫。理解各算法時空權衡、穩定性、適應性,方能因地制宜。