查找是計算機科學中最基礎、最高頻的操作之一。無論是數據庫索引、編譯器符號表、緩存系統還是業務代碼中的 Map 查詢,核心都在於如何在數據集合中高效定位目標。本文系統梳理四大經典查找範式——順序查找、二分查找、二叉搜索樹、哈希表,從原理、代碼實現、複雜度分析到工程選型,構建完整知識體系。
適用場景:無序數據、極小規模 (n < 50)、單次查詢、數據流流式處理。
int linear_search(const int arr[], int len, int target) {
if (!arr || len <= 0) return -1;
for (int i = 0; i < len; i++) {
if (arr[i] == target) return i;
}
return -1;
}
| 指標 | 數值 | 說明 |
|---|---|---|
| 時間復雜度 | O(n) | 最好 O(1),最壞 O(n),平均 n/2 次比較 |
| 空間復雜度 | O(1) | 原地操作 |
| 數據要求 | 無序/有序均可 | 無前置條件 |
核心前提:數組必須有序(升序或降序)。
關鍵技巧:mid = left + ((right - left) >> 1) 防止 left + right 溢出;循環條件 left <= right 確保單元素區間被檢查。
int binary_search(const int arr[], int len, int target) {
if (!arr || len <= 0) return -1;
int left = 0, right = len - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
| 指標 | 數值 | 說明 |
|---|---|---|
| 時間復雜度 | O(log n) | 每輪排除一半,7 元素 ≤ 3 次,15 元素 ≤ 4 次 |
| 空間復雜度 | O(1) | 迭代版;遞歸版 O(log n) 棧空間 |
| 數據結構 | 連續內存 (數組/Vector) | 需支持隨機訪問 O(1) |
工程陷阱:頻繁插入/刪除導致維護有序數組代價高昂 (O(n) 移動),此時優先考慮平衡樹或跳表。
定義:對任意節點,左子樹鍵值 < 節點鍵值 < 右子樹鍵值。
typedef struct Node {
int key;
struct Node *left, *right;
} Node;
const Node* bst_search(const Node* root, int key) {
if (!root) return NULL;
if (key == root->key) return root;
else if (key < root->key) return bst_search(root->left, key);
else return bst_search(root->right, key);
}
| 指標 | 平均情況 | 最壞情況 | 備註 |
|---|---|---|---|
| 查找/插入/刪除 | O(log n) | O(n) | 退化為鏈表 (如有序插入) |
| 空間 | O(n) | 指針開銷大 | |
生產級選型:紅黑樹 (RB-Tree) / AVL 樹 / B+ 樹 — 自平衡保證 O(log n) 最壯界,是 std::map、MySQL InnoDB 索引、Linux 虛擬內存區管理的底層結構。
核心思想:索引 = Hash(Key) % TableSize,將鍵映射到桶,桶內用鏈表/開放寬址解決衝突。
typedef struct HashNode {
int key;
struct HashNode *next;
} HashNode;
HashNode* hash_search(HashNode* buckets[], int mod, int key) {
int idx = key % mod;
HashNode* cur = buckets[idx];
while (cur) {
if (cur->key == key) return cur;
cur = cur->next;
}
return NULL;
}
| 指標 | 理想情況 | 退化情況 | 關鍵參數 |
|---|---|---|---|
| 查找/插入/刪除 | O(1) | O(n) | 負載因子 α = n/m |
| 空間 | O(n+m) | 桶數組 + 節點 | |
工程必知:
| 業務特徵 | 首選方案 | 備選/補充 |
|---|---|---|
| 靜態只讀、頻繁查找、內存受限 | 有序數組 + 二分 | 完美哈希 (gperf) |
| 動態增刪、需有序遍歷/範圍查詢 | 紅黑樹 / B+ 樹 | 跳表 (Redis ZSET) |
| 動態增刪、僅需精確匹配、極致性能 | 哈希表 | 布隆過濾器 (預過濾) |
| 鍵為字符串、前綴匹配/自動補全 | Trie 字典樹 / 雙數組 Trie | 壓縮 Trie (Radix Tree) |
| 海量數據、磁盤存儲、範圍查詢 | B+ 樹 / LSM Tree | RocksDB / LevelDB |
查找算法沒有銀彈,只有基於數據特徵、訪問模式、硬體約束的工程權衡。掌握四大範式的核心機制與邊界條件,才能在架構設計與性能調優中遊刃有餘。下一篇將進入排序算法領域,探討如何將「無序」轉化為「有序」的計算藝術。