std::lower_bound比手写二分更安全,因其自动处理边界条件、整数溢出和迭代器失效;C++20起可用std::midpoint避免回绕;查找失败时推荐返回迭代器或std::optional,避免无符号类型下-1转极大值的bug。
std::lower_bound 为什么比手写二分更安全
因为边界条件、溢出、迭代器失效这些坑,
全部帮你兜底了。手写容易在
它要求容器已排序(升序),且支持随机访问迭代器(
、
可用,
不行)
返回第一个 ≥ 目标值的迭代器,没找到就返回
,不用自己判空
内部用的是半开区间
,和绝大多数 STL 算法一致,不会因闭区间习惯出错
整数下标场景下,别直接用
算中点:
可能溢出;
内部用
安全处理
手写二分时 mid 计算必须用 left + (right - left) / 2
不是为了“看起来高级”,是防止
和
都接近
时加法溢出 —— 这种溢出不报错,但结果变成负数,后续下标访问直接 UB(未定义行为)。
错误写法:
正确写法:
如果用
或其他无符号类型,还得多一层检查:
,否则
会回绕成极大正数
C++20 起可用
,它自动处理有/无符号、溢出、指针等所有情况
查找失败时返回什么值最容易引发逻辑 bug
很多人默认返回
,但在无符号类型(如
)上下文中,
会变成极大正数(如
),后续用作索引或比较时悄无声息地出错。
统一用有符号整型(如
)做返回值,或直接返回迭代器(推荐)
若必须返回下标,检查调用方是否可能将返回值赋给
:比如
—— 这里
是
就崩了
更稳妥的做法是返回
(C++17+),调用方必须显式判断是否有值
std::binary_search 只告诉你“在不在”,但你往往需要位置
返回
,适合纯存在性判断;但多数真实场景要的是下标、插入点或范围(比如找所有等于某值的元素)。
C知道
CSDN推出的一款AI技术问答工具
下载
立即学习
“
C++免费学习笔记(深入)
”;
要下标:用
,然后减去
得到索引
要插入位置(保持有序):
的返回迭代器就是该插的位置
要找一段相等值:配合
,
就是完整区间
注意:三个函数都要求严格升序;如果容器是降序,得传
作为比较器,否则行为未定义
边界条件、迭代器有效性、类型符号性 —— 这些地方不写注释、不加断言、不测极端输入,上线后出问题根本看不出哪来的。
std::lower_boundleft 和 left 之间反复横跳,一不留神就死循环或越界。vectorarraylistend()[first, last)intmid = (left + right) / 2std::lower_boundstd::distanceleftrightINT_MAXmid = (left + right) / 2mid = left + (right - left) / 2size_tright >= leftright - leftstd::midpoint(left, right)-1size_t-118446744073709551615intsize_tauto idx = binary_search(...); vector.at(idx);idx-1std::optionalstd::binary_searchboolstd::lower_boundbegin()std::lower_boundstd::upper_bound[lower_bound, upper_bound)std::greater()