酷代码 AI
菜单
服务商

C++ 二分查找在有序数组中查找特定元素位置并正确处理未找到情况

好的,我们来分析一下禾木同学的程序问题,并给出正确的C++实现。 ## 🔍 问题分析 禾木同学遇到的是一个典型的**二分查找**问题,但有几个关键点需要注意: 1. **数组已排序** — 从小到大排好序,这是二分查找的前提条件。 2. **查找目标** — 找到等于 `k` 的数字在第几个位置(从1开始计数)。 3. **未找到时** — 输出 `n+1`,而不是常见的 `-1` 或 `0`。 4. **数据规模** — `n <= 100000`,线性查找虽然简单但效率较低(最坏 O(n)),而二分查找 O(log n) 更高效。 常见错误可能包括: - 索引从0开始,而题目要求从1开始输出。 - 边界条件处理不当,比如 `left` 和 `right` 的更新逻辑。 - 没有正确处理未找到的情况。 --- ## 💻 正确代码实现(C++) ```cpp #include <iostream> using namespace std; int main() { int n; cin >> n; int arr[100001]; // 多开一个空间,方便从1开始索引(可选) for (int i = 1; i <= n; i++) { cin >> arr[i]; } int k; cin >> k; int left = 1, right = n; int ans = -1; // 初始化为-1,表示未找到 // 二分查找 while (left <= right) { int mid = left + (right - left) / 2; // 防止溢出 if (arr[mid] == k) { ans = mid; // 记录位置 break; // 找到即退出(因为数组无重复,第一个找到的就是唯一) } else if (arr[mid] < k) { left = mid + 1; } else { right = mid - 1; } } // 输出结果:找到则输出位置,否则输出n+1 if (ans == -1) { cout << n + 1 << endl; } else { cout << ans << endl; } return 0; } ``` --- ### 📌 代码关键点解释 - **数组索引**:这里我们选择从 `1` 到 `n` 存储数据,便于直接输出位置编号。 - **二分查找**: - `left = 1, right = n`:搜索范围是整个数组。 - `mid = left + (right - left) / 2`:避免 `(left + right)` 可能溢出。 - 判断 `arr[mid]` 与 `k` 的关系来缩小范围。 - **找到即退出**:因为数组是严格排序且**无重复元素**,所以一旦找到直接输出并结束。 - **未找到输出 n+1**:用 `ans` 标记是否找到,若 `ans` 仍为 -1,则输出 `n+1`。 --- ## ✅ 对样例的验证 ### 样例1 输入: ``` 5 1 3 5 7 9 3 ``` 输出: ``` 2 ``` 正确,因为 3 是第 2 个元素。 ### 样例2 输入: ``` 2 1 2 2 ``` 输出: ``` 2 ``` 正确,因为 2 是第 2 个元素。 --- ## 🧰 进阶使用建议 1. **如果数组存在重复元素**:需要找到第一个等于 `k` 的位置,则二分查找找到 `k` 后不立即退出,而是继续向左搜索: ```cpp if (arr[mid] == k) { ans = mid; right = mid - 1; // 继续向左 } ``` 2. **如果数组从0开始索引**,输出时加1即可: ```cpp cout << ans + 1 << endl; ``` 3. **使用标准库函数**:C++ 标准库提供了 `binary_search`、`lower_bound`、`upper_bound`,可以简化代码: ```cpp #include <algorithm> int* pos = lower_bound(arr + 1, arr + n + 1, k); if (pos != arr + n + 1 && *pos == k) { cout << (pos - arr) << endl; // 输出从1开始的位置 } else { cout << n + 1 << endl; } ``` --- ## 💡 开发上的几点建议 - **务必注意边界条件**:二分查找中最常见的 bug 就是 `left` 和 `right` 的初始值与更新逻辑不匹配。 - **测试要覆盖“找不到”的情况**:比如 `k` 小于最小数、大于最大数、在数组中间但不存在。 - **命名清晰**:变量名如 `left`、`right`、`mid` 比 `l`、`r`、`m` 更易读。 - **避免魔数**:像 `100001` 这样的常量可用 `const int MAXN = 100001;` 并加上注释。 - **使用 `using namespace std;` 在小型练习代码中没问题,但在大型项目中建议避免以减少命名冲突。** --- ######[AI写代码神器 | 1181点数解答 | 2026-05-29 19:24:24]

相关提问
本站限时免费提问中
实用工具查看更多
Linux在线手册 [开发类]
Jquery在线手册 [开发类]
今日油价 [生活类]
图片互转base64 [开发类]
时间转换器 [开发类]