upper_bound和lower_bound用法(史上最全)

这篇具有很好参考价值的文章主要介绍了upper_bound和lower_bound用法(史上最全)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


两者都是定义在头文件<algorithm>里。用 二分查找的方法在一个排好序的数组中进行查找。既然是二分,时间复杂度就是O(logN)。

基础用法

upper_bound(begin, end, value)

从小到大的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个大于value的数,找到返回该数字的地址,没找到则返回end。

lower_bound(begin, end, value)

从小到大的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个大于等于value的数,找到返回该数字的地址,没找到则返回end。

用greater<type>()重载

upper_bound(begin, end, value, greater<int>())

从大到小的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个小于value的数,找到返回该数字的地址,没找到则返回end。

lower_bound(begin, end, value, greater<int>())

从大到小的排好序的数组中,在数组的 [begin, end) 区间中二分查找第一个小于等于value的数,找到返回该数字的地址,没找到则返回end。

前两部分的代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
    // 1.基础用法
    vector<int> increasing = {1,2,3,4,5};
    int pos = upper_bound(increasing.begin(), increasing.end(), 3) - increasing.begin();
    cout << increasing[pos] << endl;   // 4(第一个大于3的数)
    pos = lower_bound(increasing.begin(), increasing.end(), 3) - increasing.begin();
    cout << increasing[pos] << endl;   // 3(第一个大于等于3的数)
    bool res = upper_bound(increasing.begin(), increasing.end(), 5) == increasing.end();
    cout << res << endl;               // 1 (true,即:第一个大于5的数不存在)
    // 2.greater重载
    vector<int> decreasing = {5,4,3,2,1};
    pos = upper_bound(decreasing.begin(), decreasing.end(), 3, greater<int>()) - decreasing.begin();
    cout << decreasing[pos] << endl;   // 2(第一个小于3的数)
    pos = lower_bound(decreasing.begin(), decreasing.end(), 3, greater<int>()) - decreasing.begin();
    cout << decreasing[pos] << endl;   // 3(第一个小于等于3的数)
    res = lower_bound(decreasing.begin(), decreasing.end(), 0, greater<int>()) == decreasing.end();
    cout << res << endl;               // 1 (true,即:第一个小于等于0的数不存在)
    return 0;
}

到这里还是比较好理解的,不加greater是大于/大于等于,加上greater就是小于/小于等于。upper_bound是不带等号的,lower_bound就是带等号的。一般博客到这里就结束了,如果想要更加灵活的使用,那么请接着看。

进阶用法(自定义匿名函数)

upper_bound进阶
upper_bound(begin, end, value, cmp)
bool cmp(value, element)

upper_bound的第四个参数是自定义的匿名函数cmp,返回值为bool类型,cmp有两个参数,一个是value,对,你没看错,就是upper_bound的第3个参数value,另一个是element,也就是查找过程中与value比较的那个数。upper_bound返回的就是[begin, end)区间中第一个满足cmp(value, element)为true的数。下面看两个例子,注意看注释,方便理解。

pos = upper_bound(increasing.begin(), increasing.end(), 3, [](int value, int element) -> bool {
    return value < element;
}) - increasing.begin();           // 等价于基础用法中的第1句
cout << increasing[pos] << endl;   // 4(value是3,第一个大于value的数)

其中[](int value, int element) -> bool {return value < element;}就是匿名函数,对于c++匿名函数的用法这里就不说了,自行百度。

pos = upper_bound(increasing.begin(), increasing.end(), 3, [](int value, int element) -> bool {
    return value <= element;
}) - increasing.begin();           // 等价于基础用法中的第2句
cout << increasing[pos] << endl;   // 3(value是3,第一个大于等于value的数)

没想到,upper_bound竟然用出了lower_bound的效果!这就是自定义函数的优点了,使用灵活,这里只是举一个例子展示一下,对于更复杂的情况,比如在一个有序的vector<vector<int>>中,想查找第一个满足第2个元素大于value的vector,匿名函数就可以写成:

[](int value, vector<int> element) -> bool {return value < element[1];}
lower_bound进阶
lower_bound(begin, end, value, cmp)
bool cmp(element, value)

注意,lower_bound的匿名函数element和value的顺序反过来了!lower_bound返回的是[begin, end)区间中第一个使cmp(element, value)为false的数。

pos = lower_bound(increasing.begin(), increasing.end(), 3, [](int element, int value) -> bool {
    return element < value;
}) - increasing.begin();           // 等价于基础用法中的第2句
cout << increasing[pos] << endl;   // 3(value是3,第一个大于等于value的数)
pos = lower_bound(increasing.begin(), increasing.end(), 3, [](int element, int value) -> bool {
    return element <= value;
}) - increasing.begin();           // 等价于基础用法中的第1句
cout << increasing[pos] << endl;   // 4(value是3,第一个大于value的数)

可以看出,lower_bound也可以用出upper_bound的效果。对于更复杂的情况,读者可以自己探索。

以上,任何一个用法都需要有序,否则无法进行二分查找。文章来源地址https://www.toymoban.com/news/detail-582960.html

所有代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    // 1.基础用法
    vector<int> increasing = {1,2,3,4,5};

    int pos = upper_bound(increasing.begin(), increasing.end(), 3) - increasing.begin();
    cout << increasing[pos] << endl;   // 4(第一个大于3的数)

    pos = lower_bound(increasing.begin(), increasing.end(), 3) - increasing.begin();
    cout << increasing[pos] << endl;   // 3(第一个大于等于3的数)

    bool res = upper_bound(increasing.begin(), increasing.end(), 5) == increasing.end();
    cout << res << endl;               // 1 (true,即:第一个大于5的数不存在)

    // 2.greater重载
    vector<int> decreasing = {5,4,3,2,1};

    pos = upper_bound(decreasing.begin(), decreasing.end(), 3, greater<int>()) - decreasing.begin();
    cout << decreasing[pos] << endl;   // 2(第一个小于3的数)

    pos = lower_bound(decreasing.begin(), decreasing.end(), 3, greater<int>()) - decreasing.begin();
    cout << decreasing[pos] << endl;   // 3(第一个小于等于3的数)

    res = lower_bound(decreasing.begin(), decreasing.end(), 0, greater<int>()) == decreasing.end();
    cout << res << endl;               // 1 (true,即:第一个小于等于0的数不存在)

    // 3.进阶用法
    pos = upper_bound(increasing.begin(), increasing.end(), 3, [](int value, int element) -> bool {
        return value < element;
    }) - increasing.begin();           // 等价于基础用法中的第1句
    cout << increasing[pos] << endl;   // 4(value是3,第一个大于value的数)

    pos = upper_bound(increasing.begin(), increasing.end(), 3, [](int value, int element) -> bool {
        return value <= element;
    }) - increasing.begin();           // 等价于基础用法中的第2句
    cout << increasing[pos] << endl;   // 3(value是3,第一个大于等于value的数)

    pos = lower_bound(increasing.begin(), increasing.end(), 3, [](int element, int value) -> bool {
        return element < value;
    }) - increasing.begin();           // 等价于基础用法中的第2句
    cout << increasing[pos] << endl;   // 3(value是3,第一个大于等于value的数)

    pos = lower_bound(increasing.begin(), increasing.end(), 3, [](int element, int value) -> bool {
        return element <= value;
    }) - increasing.begin();           // 等价于基础用法中的第1句
    cout << increasing[pos] << endl;   // 4(value是3,第一个大于value的数)
    
    return 0;
}

到了这里,关于upper_bound和lower_bound用法(史上最全)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【QT】史上最全最详细的QSS样式表用法及用例说明

    Qt样式表支持各种属性、伪状态和子控件,可以自定义小部件的外观。 Widget 如何设置 QWidget 只支持 background , background-clip 和 background-origin 属性。 如果你继承于QWidget,那么你需要为你自定义的QWidget提供一个paintEvent,如下所示: 如果没有进行QSS样式表设置,上面的代码就是一

    2024年02月03日
    浏览(39)
  • Linux史上最全教程

    我们所熟知的计算机是由硬件和软件组成。 硬件:计算机系统中由电子,机械和光电子元件等组成的各种物理装置装置的统称; 简单来说硬件就是看得见摸得到的。   软件:是用户和计算机硬件之间的接口和桥梁,用户通过软件和计算机进行交流。而我们要学习的Linux就是

    2024年02月03日
    浏览(29)
  • 史上最全的排序讲解

    目录  1、插入排序 思路 实现  2、希尔排序 思路 实现  3、选择排序 思路 实现   4、堆排序 思路 实现  5、冒泡排序  思路 实现  6、快速排序  方法一:霍尔快排法 方法二:挖坑法  方法三:前后指针法   7、归并排序 思路 实现  把待排序的记录按其关键码值的大小逐

    2024年02月03日
    浏览(25)
  • .NET 6 史上最全攻略

    欢迎使用.NET 6。今天的版本是.NET 团队和社区一年多努力的结果。C# 10 和F# 6 提供了语言改进,使您的代码更简单、更好。性能大幅提升,我们已经看到微软降低了托管云服务的成本。.NET 6 是第一个原生支持Apple Silicon (Arm64) 的版本,并且还针对Windows Arm64 进行了改进。我们构

    2024年02月04日
    浏览(46)
  • 史上最全Oracle语法合集

    查询 排序 集合 并集: 交集 :intersect 差集 :minus 联合查询 : 子查询 : 分页SQL: 创建表空间: 修改表空间: 修改原有数据文件大小: 临时表空间 创建用户: 修改用户: 系统权限: 对象权限: 删除用户: 创建表: 删除表: 约束: 给表添加列 删除表中的一个列 修改一

    2024年02月14日
    浏览(28)
  • 史上最全ThreadLocal 详解(二)

    ThreadLocal 内存泄露的原因及处理方式 目录 1、ThreadLocal 使用原理 2、ThreadLocal 内存泄露的原因 3、 为什么不将key设置为强引用 3.1 、key 如果是强引用 3.2、key 如果是强引用 3.3  那么为什么 key 要用弱引用 3.4 如何正确的使用ThreadLocal        前文我们讲过ThreadLocal的主要用途是

    2024年02月02日
    浏览(37)
  • spring security (史上最全)

    一般意义来说的应用访问安全性,都是围绕认证(Authentication)和授权(Authorization)这两个核心概念来展开的。 即: 首先需要确定用户身份, 再确定这个用户是否有访问指定资源的权限。 认证这块的解决方案很多,主流的有 CAS 、 SAML2 、 OAUTH2 等(不巧这几个都用过-_-),

    2024年02月06日
    浏览(30)
  • CAN矩阵(入门篇)(史上最全)

    CAN矩阵 ADAS CAN矩阵 JM相机CAN矩阵 CAN消息及信号的含义 CAN消息解析 实际值=(十进制*Factor)+Offset 实车上如何利用该CAN消息 JM相机CAN消息利用分为以下几个部分 车道线点适配 车道线识别状态适配 车道线属性适配 轨迹推定适配 承泰雷达CAN矩阵讲解 承泰雷达的重要输出 ObjectL

    2024年02月01日
    浏览(29)
  • 史上最全midjourney关键词

    最全midjourney,篇幅太长,文章最后有可编辑版本获取链接 增强图片真实感、清晰度 unreal engine 虚幻引擎 ultra realistic 超真实 photography 摄影图片 detailed 细节 4K 4K质 8K 8K画质 octane render OC渲染器 realistic 现实主义的 epic epic游戏质感 3D rendering 3D渲染 35mm 35mm镜头,也可以设置

    2024年02月04日
    浏览(37)
  • adb 获取日志命令-史上最全

    adb logcat 获取的是日志buffer中从头到尾的日志,并且最新的日志会持续写入。历史日志多少取决于缓冲区大小,并且我们可以通过参数过滤掉无用的日志。可以使用xlog框架将历史日志保存(可以研究下源码)。 日志打印不了 插拔重启 日志缓冲区修改最大 usb驱动查看 adb重启

    2024年02月04日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包