std::binary_search仅返回是否存在,不提供位置;需用lower_bound或upper_bound获取下标,前者返回首个≥目标的迭代器,减begin()得下标,但须检查解引用是否等于目标。

直接说结论:std::binary_search 只能判断“是否存在”,不返回位置;真要找下标,得用 std::lower_bound 或 std::upper_bound。
为什么 binary_search 不能拿到索引
它设计目标就是布尔判定——输入一个已排序区间和值,返回 true 或 false。底层确实用了二分逻辑,但内部不暴露迭代器位置。
- 常见错误:以为
binary_search返回指针或下标,结果编译失败或误用返回值 - 它要求容器支持随机访问(如
vector、array),且必须已升序排列(或按自定义Compare排好) - 时间复杂度是
O(log n),但比手写循环多一次函数调用开销,实际差别极小
lower_bound 才是你真正需要的“找位置”函数
它返回第一个 ≥ 目标值的迭代器,减去 begin() 就是下标;如果没找到,返回 end(),此时下标等于容器大小。
vectorv = {1, 3, 5, 7, 9}; auto it = lower_bound(v.begin(), v.end(), 5); if (it != v.end() && *it == 5) { int idx = it - v.begin(); // idx == 2 }
- 注意:必须检查
*it == target,因为lower_bound找的是“不小于”,不是“等于” - 若想支持降序,传入
greater作为第 4 个参数,同时确保容器是降序排列{} - 对
vector、deque安全;对list不适用(不支持随机访问迭代器)
手写二分时最容易漏掉的边界条件
自己实现时,left 和 left 两种写法行为不同,对应不同的终止状态和下标含义。
立即学习“C++免费学习笔记(深入)”;
- 用
left :循环结束时left > right,未命中可直接返回-1 - 用
left :循环结束时left == right,需额外判断v[left] == target - 计算中点务必写成
left + (right - left) / 2,避免left + right溢出(尤其在int大数组上) - 更新边界时别写反:
if (v[mid] ,不是mid
真正用到二分的场景,往往不是“查有没有”,而是“找插入点”或“找左/右边界”。这时候 lower_bound 和 upper_bound 的语义比手写更清晰,也更难出错——但前提是记住它们不保证值一定存在,总要配一次解引用+比较。











