std::binary_search仅适用于存在性判断,无法定位元素位置;实际检索应使用std::lower_bound或std::upper_bound获取迭代器,支持插入点定位、频次统计等,且保持o(log n)复杂度。

std::binary_search 为什么不能直接替代手写二分?
它只返回 bool,不告诉你元素在哪——查到了是 true,没查到就是 false,连插入位置都给不了。真要拿来做检索主逻辑,多数时候你其实需要的是下标或迭代器,而不是“有没有”。
常见错误现象:std::binary_search 返回 true 后,再用 std::find 扫一遍找位置,白费 O(n) 时间;或者误以为它能返回匹配点,结果后续操作崩溃。
- 真正该用
std::lower_bound或std::upper_bound:它们返回迭代器,且保持 O(log n) 复杂度 -
std::binary_search仅适合纯存在性判断,比如校验数据完整性、预检条件 - 所有标准算法都要求容器已严格升序(
operator 满足严格弱序),若用自定义比较器,必须全程一致
用 std::lower_bound 查找第一个 ≥ target 的位置
这是实际检索中最常用的操作:定位插入点、统计频次、实现范围查询的起点。它比 std::binary_search 多做一点点事,但价值翻倍。
使用场景:去重数组中找某值首次出现位置;构建离散化映射表;配合 std::upper_bound 算区间长度。
立即学习“C++免费学习笔记(深入)”;
示例:
NetShop软件特点介绍: 1、使用ASP.Net(c#)2.0、多层结构开发 2、前台设计不采用任何.NET内置控件读取数据,完全标签化模板处理,加快读取速度3、安全的数据添加删除读取操作,利用存储过程模式彻底防制SQL注入式攻击4、前台架构DIV+CSS兼容IE6,IE7,FF等,有利于搜索引挚收录5、后台内置强大的功能,整合多家网店系统的功能,加以优化。6、支持三种类型的数据库:Acces
std::vector<int> arr = {1, 2, 2, 2, 3, 4, 4};
auto it = std::lower_bound(arr.begin(), arr.end(), 2);
// it 指向第一个 2,即 arr[1]
- 参数顺序固定:
begin, end, value,不能颠倒;比较器要传在最后,不是第三个参数 - 若 target 大于所有元素,返回
arr.end(),务必检查是否越界再解引用 - 对
std::vector、std::array等支持随机访问的容器,底层是真正的二分;但对std::list,它退化为线性查找(别这么干)
std::lower_bound 和 std::upper_bound 配合统计重复元素个数
有序数据里查某个值出现了几次,不用遍历,两行搞定。这是 std::binary_search 完全做不到的事。
性能影响:O(log n) 固定开销,和重复数量无关;而手写循环统计最坏 O(n)。
示例:
std::vector<int> arr = {1, 2, 2, 2, 3, 4, 4};
auto l = std::lower_bound(arr.begin(), arr.end(), 2);
auto u = std::upper_bound(arr.begin(), arr.end(), 2);
int count = std::distance(l, u); // 得到 3
-
std::upper_bound返回第一个 > target 的位置,不是 ≥ ——这点和lower_bound的语义差一个等号,极易混淆 - 如果 target 不存在,
lower_bound == upper_bound,distance为 0,安全 - 不要对
std::set或std::map用这个技巧:它们提供count()成员函数,但底层仍是 O(log n),且更简洁
自定义比较器时最容易漏掉的三个细节
一旦数据不是基础类型或排序规则特殊,比如按绝对值排、按字符串长度排、或结构体按某字段排,std::lower_bound 就必须带比较器——而且得带对。
常见错误现象:invalid comparator 运行时报错;查找结果偏移;甚至触发 undefined behavior。
- 比较器必须是**严格弱序**:不能有
a ,也不能同时满足 <code>a 和 <code>b - 调用时比较器要传在第四个参数位:
lower_bound(begin, end, val, cmp),不是第三个 - 容器本身也得用同一套比较器构建(比如
std::set<t cmp></t>),否则数据物理顺序和算法预期不一致
复杂点在于:同一个容器,不同查找目标可能需要不同比较逻辑,但标准算法不支持运行时切换;这时候要么预建多个视图,要么改用 std::equal_range + 自定义谓词封装——但别硬塞进一个函数里试图通用。









