直接用std::upper_bound最省事,它返回首个严格大于target的迭代器,要求容器升序且比较逻辑一致;手写时右边界应设为n,更新为r=mid−1,最后返回l。

二分查找找首个大于目标值的元素怎么写
直接用 std::upper_bound 最省事,它返回第一个严格大于 target 的迭代器。但要注意:它要求容器已升序排列,且比较逻辑必须一致。
手写时容易错在边界收缩条件——右边界更新不能写成 r = mid,否则可能死循环;正确是 r = mid - 1,左边界更新为 l = mid + 1,最后返回 l(即插入位置)。
- 若数组为空或所有元素 ≤
target,std::upper_bound返回end(),需判空 - 手写版本中,初始
r应设为n(而非n-1),因为答案可能落在末尾+1位置 -
std::upper_bound对vector、array、原生指针都适用,但对list不可用(不支持随机访问)
二分查找找最后一个小于目标值的元素为什么不能直接改 lower_bound
std::lower_bound 找的是第一个 ≥ target 的位置,它的前一个位置(如果存在)才是最后一个 target 的元素。但直接 --it 有风险:若 it == begin(),前置递减未定义行为。
更稳妥的做法是先调用 std::lower_bound,再检查是否非首位置且前一元素确实 target;或者手写时把判断条件设为 arr[mid] ,并让左边界“贴着”满足条件的位置走:
立即学习“C++免费学习笔记(深入)”;
int l = -1, r = n - 1;
while (l < r) {
int mid = l + (r - l + 1) / 2; // 上取整,避免 l = mid 死循环
if (arr[mid] < target) l = mid;
else r = mid - 1;
}
// l 即最后一个 < target 的下标,l == -1 表示不存在如何统一处理边界不存在时的返回值
标准库函数返回迭代器,用户需自行解引用前判断有效性;手写函数建议统一返回下标,并约定无效时返回 -1 或 n(取决于语义),避免裸指针运算。
-
std::lower_bound和std::upper_bound都不检查target是否实际存在,只管位置 - 若要同时支持「首个 ≥」和「首个 >」,别硬套同一套 while 循环逻辑——比较符和边界更新必须同步调整,稍一疏忽就会漏掉等号情况
- 浮点数二分慎用
==判断,这类变体通常应避免直接比较相等,而是依赖区间收缩逻辑
自定义类型或结构体怎么用 upper_bound 找首个大于目标的元素
关键在提供正确的比较谓词。比如有一个按 id 排序的 vector<Person>,想按 id 查首个大于 100 的人,不能传 Person{100} 直接比,而应传一个只含 id 的临时对象,并重载 operator< 或用 lambda:
auto it = std::upper_bound(vec.begin(), vec.end(), 100,
[](int val, const Person& p) { return val < p.id; }
);注意这个 lambda 参数顺序:upper_bound 要求谓词是 (value, element) 形式,表示 “value 是否应排在 element 前面”,所以是 val ,不是 <code>p.id > val。顺序反了会导致逻辑颠倒、结果错误。
这个细节被忽略时,编译可能通过,但运行结果完全不对,而且难以调试。


















