C++ 中 lower_bound 和 upper_bound 的 4 种常见用法

892264892 发布于 2026-04-17 78 次阅读


AI 摘要

很多人对C++的`lower_bound`和`upper_bound`用混,根源在于没分清排序方向对语义的影响。文章的核心价值在于:不仅明确升序默认分别找≥x和>x的边界位置,更重点拆解配合`greater<int>()`后,在降序数组中语义会反转成≤x和<x;同时提醒返回值是位置而非元素,并需警惕尾后越界。

在 C++ 里,lower_boundupper_bound 是非常常用的二分查找函数。
它们最重要的作用,不是单纯判断一个数在不在数组里,而是在有序区间中查找边界位置

很多人刚接触这两个函数时,最容易混淆两点:

  1. 它们返回的是位置,不是元素值。
  2. 在升序和降序数组中,它们的含义并不一样,尤其是配合 greater<int>() 时更要分清楚。

这篇文章就把这 4 种最常见的写法一次讲明白。

1. 升序数组中的用法

先看一个升序数组:

int num[] = {1, 3, 5, 7, 7, 9};

如果我们查找数字 7

int pos1 = lower_bound(num, num + 6, 7) - num;
int pos2 = upper_bound(num, num + 6, 7) - num;

它们分别表示:

  • lower_bound(num, num + 6, 7):返回第一个大于或等于 7 的位置
  • upper_bound(num, num + 6, 7):返回第一个大于 7 的位置

代入这个数组:

  • pos1 = 3,因为 num[3] = 7,这是第一个大于等于 7 的元素
  • pos2 = 5,因为 num[5] = 9,这是第一个大于 7 的元素

所以在升序数组中:

lower_bound -> 找 >= x 的第一个位置
upper_bound -> 找 >  x 的第一个位置

2. 降序数组中的用法

如果数组是降序的,就不能直接用默认写法了。
这时要配合比较器 greater<int>()

例如:

int num[] = {9, 7, 7, 5, 3, 1};

查找 7

int pos3 = lower_bound(num, num + 6, 7, greater<int>()) - num;
int pos4 = upper_bound(num, num + 6, 7, greater<int>()) - num;

这时含义会变成:

  • lower_bound(num, num + 6, 7, greater<int>()):返回第一个小于或等于 7 的位置
  • upper_bound(num, num + 6, 7, greater<int>()):返回第一个小于 7 的位置

放到数组里:

  • pos3 = 1,因为 num[1] = 7,这是第一个小于或等于 7 的元素
  • pos4 = 3,因为 num[3] = 5,这是第一个小于 7 的元素

所以在降序数组中:

lower_bound + greater<int>() -> 找 <= x 的第一个位置
upper_bound + greater<int>() -> 找 <  x 的第一个位置

3. 这 4 行代码到底是什么意思

你给的代码可以这样理解:

int pos1=lower_bound(num,num+6,7)-num; 
// 返回升序数组中第一个大于或等于 7 的位置

int pos2=upper_bound(num,num+6,7)-num; 
// 返回升序数组中第一个大于 7 的位置

int pos3=lower_bound(num,num+6,7,greater<int>())-num; 
// 返回降序数组中第一个小于或等于 7 的位置

int pos4=upper_bound(num,num+6,7,greater<int>())-num; 
// 返回降序数组中第一个小于 7 的位置

注意最后的 - num

因为 lower_boundupper_bound 返回的是指针或迭代器,减去数组首地址以后,得到的才是我们平时说的“下标位置”。

4. 一张表记住 4 种写法

写法数组顺序含义
lower_bound(begin, end, x)升序第一个 >= x 的位置
upper_bound(begin, end, x)升序第一个 > x 的位置
lower_bound(begin, end, x, greater<int>())降序第一个 <= x 的位置
upper_bound(begin, end, x, greater<int>())降序第一个 < x 的位置

这张表基本就是这道知识点的核心。

5. 使用时最容易踩的坑

5.1 数组必须有序,而且排序方向要匹配

  • 默认写法要求区间是升序
  • 使用 greater<int>() 时,区间必须是降序

如果顺序不对,结果就不可靠。

5.2 返回的是位置,不是元素值

例如:

int pos = lower_bound(num, num + 6, 7) - num;

这里的 pos 是位置,不是 7 本身。

如果你想拿到这个位置对应的值,还得再写:

int value = num[pos];

当然前提是 pos 没有越界。

5.3 找不到时可能返回尾后位置

例如在升序数组 {1, 3, 5} 中查找 10

int pos = lower_bound(num, num + 3, 10) - num;

这时 pos 会等于 3,也就是区间末尾的后一个位置。

所以实际做题时,拿到结果后通常要判断:

if (pos < n) {
    // 位置有效
}

6. 总结

lower_boundupper_bound 的本质,都是在有序区间里找边界。

在升序数组中:

  • lower_bound 找第一个 >= x
  • upper_bound 找第一个 > x

在降序数组中,配合 greater<int>()

  • lower_bound 找第一个 <= x
  • upper_bound 找第一个 < x

只要把这 4 种情况分清楚,STL 二分函数这一块基本就不会再混了。