std::lower_bound和std::upper_bound可直接用于二分查找:前者找首个≥target位置,后者找首个>target位置,二者结合得target的完整迭代器范围,适用于随机访问容器。
绝大多数场景下,std::lower_bound 和 std::upper_bound 就是你要的二分查找。它们要求容器已排序(或传入相同比较器),时间复杂度 O(log n),且经过标准库充分测试,边界处理比手写更可靠。
std::lower_bound
std::upper_bound
std::vector、普通数组指针、std::array 都适用,只要支持随机访问迭代器取决于你定义的搜索区间是闭区间 [left, right] 还是左闭右开 [left, right)。前者常用 left ,后者必须用 left 。混用会导致死循环或越界。
right = vec.size() - 1,循环条件 left ,更新时 right = mid - 1 / left = mid + 1
right = vec.size(),循环条件 left ,更新时 right = mid / left = mid + 1
-1;左闭右开习惯返回 left(即插入位置),需额外判断 vec[left] == target
如果你的容器元素不是基础类型(比如 struct 或 class),或想按特定字段查找,必须确保 std::lower_bound 的第三个参数(比较函数)与容器排序所用逻辑完全一致。否则行为未定义。
std::sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) { return a.id
std::lower_bound(vec.begin(), vec.end(), target_id, [](const auto& e, int id) { return e.id
(value_type, T) 或 (T, value_
type),取决于你是查“小于 target”还是“target 小于某值”——lower_bound 要求的是 comp(value, target) == true 表示 value 在 target 前#include#include #include struct Person { int id; std::string name; };
int main() { std::vector
people = {{1,"Alice"}, {3,"Bob"}, {5,"Charlie"}, {7,"Diana"}}; // 按 id 排序(已满足) int target = 5; auto it = std::lower_bound(people.begin(), people.end(), target, [](const Person& p, int id) { return p.id zuojiankuohaophpcn id; }); if (it != people.end() && it-youjiankuohaophpcnid == target) { std::cout zuojiankuohaophpcnzuojiankuohaophpcn "Found: " zuojiankuohaophpcnzuojiankuohaophpcn it-youjiankuohaophpcnname zuojiankuohaophpcnzuojiankuohaophpcn "\n"; } else { std::cout zuojiankuohaophpcnzuojiankuohaophpcn "Not found\n"; }}
浮点数二分要小心精度和终止条件
对浮点数做二分(比如解方程、找阈值),不能依赖
left == right终止。必须设定精度容差(如1e-6)或最大迭代次数,否则可能死循环。
- 避免用
while (left 直接比较浮点数- 推荐用迭代次数控制:
for (int i = 0; i —— 100 次足够把区间缩小到1e-30级别- 或者用
while (right - left > eps),但需确保eps大于浮点数的机器精度(std::numeric_limits是相对误差,不适用于此)::epsilon() - mid 计算建议用
mid = left + (right - left) / 2.0,避免left + right溢出(对 double 影响小,但写成习惯更安全)实际用的时候,先看能不能走
std::lower_bound;非要手写,就盯死区间定义和终止条件;查浮点数,别信相等判断。