二分查找是算法入門必修課。用指針算術替代下標索引,不僅能加深對 C 語言內存模型的理解,更能在嵌入式開發、底層庫編寫中寫出更緊湊、高效的代碼。本文基於一個遞歸版實現,重點剖析指針偏移邏輯、遞歸終止條件、以及常見的「無限遞歸」陷阱。
#include <stdio.h>
// 函數聲明:low/high 為下標邊界,ptr 指向數組首地址
int binsearch(int low, int high, int *ptr, int value);
int main() {
int arr[10];
int *ptr = arr; // 指向首元素
// ... 輸入數據 (假設已升序排列) ...
int m; scanf("%d", &m);
int pos = binsearch(0, 9, ptr, m);
if (pos != -1) printf("找到於下標 %d, 值 %d\n", pos, *(ptr + pos));
else printf("未找到\n");
return 0;
}
// 遞歸二分查找
int binsearch(int low, int high, int *ptr, int value) {
// 1. 遞歸基線條件:區間無效
if (ptr == NULL || low > high) return -1;
// 2. 邊界快速判斷 (優化: 減少遞歸深度)
if (*(ptr + low) == value) return low;
if (*(ptr + high) == value) return high;
// 3. 區間縮減至單元素
if (low == high) return -1; // 上已判斷過 low/high 不等於 value
// 4. 計算中點 (防溢出寫法: low + (high - low) / 2)
int mid = low + (high - low) / 2;
int mid_val = *(ptr + mid);
// 5. 核心遞歸分支
if (mid_val == value) {
return mid;
} else if (mid_val > value) {
return binsearch(low, mid - 1, ptr, value); // 左半區間
} else {
return binsearch(mid + 1, high, ptr, value); // 右半區間
}
}
*(ptr + mid) 等價於 ptr[mid],編譯器生成相同機器碼。ptr + offset 並調整 low/high 為相對下標,無需複製數組。low > high:標準區間為空判斷。low == high:單元素區間,若前序邊界檢查未命中,直接返回 -1。ptr == NULL:防禦性編程,防止空指針解引用。常見錯誤:僅判斷 low > high 而漏掉 low == high 的顯式處理,導致 mid = low 陷入 binsearch(low, mid-1, ...) 或 binsearch(mid+1, high, ...) 形成 low > high 才終止,雖正確但多一次遞歸。
// 錯誤示範:導致無限遞歸 if (mid_val > value) return binsearch(low, mid, ptr, value); // mid 未排除 // 正確寫法: if (mid_val > value) return binsearch(low, mid - 1, ptr, value); // 排除 mid
原代碼中 mid-1 和 mid+1 確保了區間長度單調遞減,遞歸深度上限為 $O(\log n)$。
(low + high) / 2 在 low + high > INT_MAX 時溢出(雖本例 n=10 無礙)。標準寫法:low + (high - low) / 2 或 (low + high) >> 1 (無符號數安全)。
| 維度 | 遞歸版 | 迭代版 |
|---|---|---|
| 代碼可讀性 | ⭐⭐⭐⭐⭐ (邏輯直觀) | ⭐⭐⭐⭐ |
| 棧空間 | $O(\log n)$ 幀 | $O(1)$ |
| 函數調用開銷 | 有 (入棧/出棧) | 無 |
| 編譯器優化 | 尾調用優化 (TCO) 可能消除棧增長 | 天然無開銷 |