binary_search返回bool因其仅判断存在性而不提供位置信息;需下标时应使用std::lower_bound并检查是否等于end()。

binary_search 为什么返回 bool 而不是下标
因为它的设计目标只有一个:查“有没有”。它不关心在哪,只回答“存在吗”。这和 std::lower_bound、std::upper_bound 的定位完全不同——后两者才负责定位。
常见错误现象:binary_search 返回 true,但你接着去访问 v[0] 或硬算下标,结果越界或逻辑错乱。它根本不提供位置信息。
- 如果你需要下标,直接用
std::lower_bound,然后检查是否等于end() - 如果容器是
std::vector且已排序,binary_search(v.begin(), v.end(), x)是安全的;但若未排序,结果未定义(不是报错,而是可能返回任意 bool) - 注意:迭代器范围必须满足严格弱序,比如自定义比较函数时,
comp(a, a)必须为false,否则行为未定义
传入自定义比较函数时最容易漏掉的条件
用 binary_search 查结构体或自定义类型时,很多人只写 comp(a, b),却忘了它必须和排序时用的是**同一个函数对象**。
错误示例:用 std::sort(v.begin(), v.end(), [](auto& x, auto& y) { return x.id 排序,但调用 <code>binary_search 时漏传比较函数,或传了另一个逻辑(比如按 name 比),结果永远返回 false —— 因为底层二分依赖的序关系和实际数据排列不一致。
立即学习“C++免费学习笔记(深入)”;
- 务必配对使用:排序用什么比较器,查找也得传什么比较器
- lambda 捕获变量需注意生命周期:如果比较函数捕获了局部变量,而容器生命周期更长,运行时可能读到野值
- 函数对象类型要一致:不能一个用
std::less,另一个用手写 lambda,即使逻辑相同,类型不同也会导致模板实例化失败
在 std::set / std::map 上调用 binary_search 是多此一举
std::set 和 std::map 底层是红黑树,自带 find() 成员函数,平均 O(log n),且返回迭代器,既能判断存在性又能取值。此时用全局 binary_search 不仅冗余,还容易出错。
典型误用:binary_search(s.begin(), s.end(), x) —— 看似可行,但 std::set::iterator 是 const 迭代器,某些标准库实现会因类型推导问题编译失败;更重要的是,它绕过了容器自己的优化路径。
- 对
std::set,直接用s.find(x) != s.end() - 对
std::map,用m.find(key) != m.end()或更简洁的m.count(key)(注意count对 map 永远是 0 或 1) - 只有面对原始数组、
std::vector、std::array这类“无查找能力”的序列时,binary_search才是合理选择
性能陷阱:迭代器类型影响是否真走二分
binary_search 要求随机访问迭代器(RandomAccessIterator)才能达到 O(log n)。如果误传了 std::list::iterator 或 std::forward_list::iterator,代码仍可能编译通过(取决于标准库实现),但内部会退化成线性遍历 —— 完全失去二分意义。
错误信号:明明数据量上万,查找却慢得反常,且 CPU 占用集中在循环判断上。这不是算法问题,是迭代器类型没达标。
- 安全组合:只对
std::vector、std::deque、std::array、原生指针(如&arr[0])使用binary_search - 不确定时,用
std::is_same_v<typename it::iterator_category std::random_access_iterator_tag></typename>静态断言(C++20 可用std::random_access_iterator概念) - 别试图对
std::vector<t>::const_iterator</t>做手脚来“适配”非随机访问容器——没用,类型不匹配就是不匹配
最常被忽略的一点:binary_search 不检查输入范围是否真有序。它假设你已经排好序,连 warning 都不会给。一旦数据没排,返回值就纯粹是垃圾,而且你还很难复现——有时候碰巧 true,有时候 false,调试起来像玄学。








