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日
    浏览(53)
  • 史上最全的排序讲解

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

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

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

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

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

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

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

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

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

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

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

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

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

    2024年02月04日
    浏览(40)
  • Python知识点(史上最全)

    Python期末考试知识点(史上最全) python简介 type()不会认为子类是一种父类类型。 isinstance()会认为子类是一种父类类型 基础语法 运算符: 算术运算符: 多了一个**,代表 幂方 5**5 就是5的5次方 还多了一个 // 整数除法 逻辑运算符: and,or,not 与,或,非 赋值运算符: 没有+

    2024年02月02日
    浏览(42)
  • 史上最全面的敏感信息收集方案

    介绍一款目录渗透工具: ffuf ffuf Fast web fuzzer written in Go,速度快,自定义性高,非常好用 这里贴出一个我常用的脚本:(这里注意域名或IP后面要加上 /FUZZ ) 语雀( http://yuque.com )是一个企业级协作服务,提供文档、表格、项目管理等协作工具,帮助企业沉淀、整理内部信

    2024年02月05日
    浏览(58)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包