std::binary_search仅返回是否找到,不返回位置;参数为迭代器范围[first,last)且容器须严格升序;需位置时应改用lower_bound配合判断。

binary_search 函数怎么用,参数顺序容易错
std::binary_search 是 C++ 标准库提供的二分查找工具,但它不返回位置,只返回 true 或 false。常见误用是把它当 lower_bound 用,结果查到了却不知道在哪。
基本调用形式是:binary_search(first, last, value),注意:前两个参数是迭代器范围,左闭右开(即 [first, last)),且容器必须已升序排列——不是“大概有序”,是严格升序,否则行为未定义。
- 如果用自定义比较函数,必须传第 4 个参数:
binary_search(v.begin(), v.end(), x, greater<int>())</int>,此时容器得是降序的 - 不能对
vector<bool></bool>直接用——它不是真正的容器,迭代器行为异常,会编译失败或运行时出错 - 对
list或其他非随机访问容器调用binary_search虽然能编译,但性能退化成 O(n),因为内部仍依赖std::distance计算中点
想拿到下标?别硬套 binary_search,改用 lower_bound
真正需要“查到就返回位置”的场景,binary_search 不够用。应该用 lower_bound 配合判断:
auto it = lower_bound(v.begin(), v.end(), x);
if (it != v.end() && *it == x) {
size_t idx = it - v.begin(); // 这才是安全的下标
}这个写法比手写二分更可靠,也比先 binary_search 再 find 更高效(避免两次遍历)。
立即学习“C++免费学习笔记(深入)”;
-
lower_bound返回第一个 ≥x的位置;upper_bound返回第一个 >x的位置;两者配合可快速统计重复元素个数 - 如果容器是降序的,记得加
greater<int>()</int>,且三个函数(lower_bound/upper_bound/binary_search)必须用同一个比较规则 - 用
std::distance(v.begin(), it)替代it - v.begin()可以兼容更多容器,但对vector来说减法更快
手写二分时,while 条件和边界更新必须统一
标准库函数封装了细节,但调试或面试时常要手写。最常出错的是循环条件和中点更新不匹配:
int l = 0, r = n; // 左闭右开区间 [l, r)
while (l < r) {
int m = l + (r - l) / 2;
if (a[m] < x) l = m + 1;
else r = m;
}这个版本和 lower_bound 行为一致。若用 l (闭区间),则初始 <code>r = n-1,更新也要改成 r = m - 1 和 l = m + 1,混用会导致死循环或越界。
- 用
(l + r) / 2可能整数溢出,尤其在指针运算或大数组下,务必写成l + (r - l) / 2 - 检查
l是否越界(如l >= n)再取值,否则a[l]可能非法访问 - 浮点二分(如求平方根)要慎设精度,用
while (r - l > 1e-7)比固定循环次数更稳妥
binary_search 在 set/map 上效率没优势
set 和 map 的 find() 方法平均复杂度就是 O(log n),且支持任意键类型(包括自定义类),而 binary_search 只能用于连续内存容器(vector、array、deque),还要手动保证有序。
更关键的是:set::find 返回迭代器,可直接读值或删元素;binary_search 返回布尔值,查完还得再找一遍位置。
- 对
vector做大量查找且数据不变时,排序 +binary_search或lower_bound是合理的 - 但如果边插边查,优先考虑
unordered_set(O(1) 平均)或保持set(O(log n) 稳定) - 用
std::span(C++20)包装原始数组再传给binary_search是安全的,但别忘了它不管理生命周期
实际用的时候,先问自己:要不要位置?数据是否已排好?会不会动态增删?这几个问题的答案,基本就决定了该用哪个函数。











