在 C++ 标准模板库(STL)中,std::lower_bound
和 std::upper_bound
是两个强大的二分查找函数,适用于 有序范围(如 std::vector
、std::set
或 std::map
)。这两个函数可以帮助我们快速找到元素的位置,支持高效的插入、统计和查找操作。
lower_bound
和 upper_bound
的区别
std::lower_bound
- 作用: 返回第一个 大于等于 (
>=
) 指定值的元素的迭代器。 - 如果值存在: 返回该值的第一个位置。
- 如果值不存在: 返回比目标值 大的第一个元素 位置。
- 如果所有元素都小于目标值: 返回
end()
迭代器。 - 反向查找小于目标值的元素:
std::lower_bound
返回的迭代器减一,即std::lower_bound(vec.begin(), vec.end(), target) - 1
。
std::upper_bound
- 作用: 返回第一个 大于 (
>
) 指定值的元素的迭代器。 - 如果值存在: 跳过所有相同值,返回比目标值 大的第一个元素 位置。
- 如果值不存在: 返回比目标值 大的第一个元素 位置。
- 如果所有元素都小于等于目标值: 返回
end()
迭代器。 - 反向查找小于等于目标值的元素:
std::upper_bound
返回的迭代器减一,即std::upper_bound(vec.begin(), vec.end(), target) - 1
。
示例代码
虽然标准库只提供了“大于”和“大于等于”的函数,但是用这两个函数,可以组合出“小于”,“小于等于”和“等于”的判定。
#include <iostream>
#include <vector>
#include <algorithm>int main() {std::vector<int> vec = {1, 2, 4, 4, 4, 6, 8, 10};int target = 4;// lower_boundauto lower = std::lower_bound(vec.begin(), vec.end(), target);std::cout << "lower_bound of " << target << " is at index: " << (lower - vec.begin()) << std::endl;// upper_boundauto upper = std::upper_bound(vec.begin(), vec.end(), target);std::cout << "upper_bound of " << target << " is at index: " << (upper - vec.begin()) << std::endl;// 找到最后一个小于 target 的元素if (lower != vec.begin()) {auto last_less = lower - 1;std::cout << "Last element less than " << target << " is " << *last_less << " at index " << (last_less - vec.begin()) << std::endl;} else {std::cout << "No element is less than " << target << std::endl;}// 找到最后一个小于等于 target 的元素if (upper != vec.begin()) {auto last_less_equal = upper - 1;std::cout << "Last element less than or equal to " << target << " is " << *last_less_equal << " at index " << (last_less_equal - vec.begin()) << std::endl;} else {std::cout << "No element is less than or equal to " << target << std::endl;}return 0;
}
运行结果
lower_bound of 4 is at index: 2
upper_bound of 4 is at index: 5
Last element less than 4 is 2 at index 1
Last element less than or equal to 4 is 4 at index 4
示例和拓展
1. 查找元素是否存在
if (lower != vec.end() && *lower == target) {std::cout << target << " exists in the array at index " << (lower - vec.begin()) << std::endl;
} else {std::cout << target << " does not exist in the array." << std::endl;
}
2. 统计目标值出现次数
int count = upper - lower;
std::cout << "Count of " << target << " is: " << count << std::endl;
3. 查找最后一个小于目标值的元素
if (lower != vec.begin()) {auto last_less = lower - 1;std::cout << "Last element less than " << target << " is " << *last_less << std::endl;
}
4. 查找最后一个小于等于目标值的元素
if (upper != vec.begin()) {auto last_less_equal = upper - 1;std::cout << "Last element less than or equal to " << target << " is " << *last_less_equal << std::endl;
}
复杂度分析
std::lower_bound
和std::upper_bound
都基于二分查找,时间复杂度为 O(log n)。- 适用于 有序序列,如果无序,则需要先排序
O(n log n)
,然后查找O(log n)
。
总结
函数 | 返回 | 若值存在 | 若值不存在 | 典型应用 |
---|---|---|---|---|
lower_bound |
第一个 >= target 的迭代器 |
目标值的第一个位置 | 第一个比它大的元素 | 查找元素、插入位置 |
upper_bound |
第一个 > target 的迭代器 |
跳过所有相同值的元素 | 第一个比它大的元素 | 计算元素出现次数 |
lower_bound - 1 |
最后一个 < target 的迭代器 |
目标值前一个元素 | 最大的小于 target 的元素 |
反向查找小于目标值 |
upper_bound - 1 |
最后一个 <= target 的迭代器 |
目标值最后一个位置 | 最大的小于等于 target 的元素 |
反向查找小于等于目标值 |