lower_bound()函数和upper_bound()函数,以及二分查找

参考C++ Refference:
http://www.cplusplus.com/reference/algorithm/lower_bound/
本文前面是函数原型, 后面是怎么用

lower_bound():

默认版本

template <class ForwardIterator, class T>
 ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
                               const T& val);

自定义比较函数版

template <class ForwardIterator, class T, class Compare>
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
                               const T& val, Compare comp);

第一个first参数是一段连续空间的首地址,last是连续空间末端的地址,val是要查找的值。调用lower_bound()的前提是这段连续的空间里的元素是有序(递增)的。
然后lower_bound()的返回值是第一个大于等于val的值的地址,用这个地址减去first,得到的就是第一个大于等于val的值的下标

在自定义版本里有一个comp参数,它的用处在于,当你要查找的不是基本数据类型,而是自己定义的struct时就需要自己定义一下,怎么比较两个struct的大小。

用法示例

默认版本

#include <iostream>
#include <algorithm>
using namespace std;
int main(int argc, char *argv[]){
    int a[] = {1, 3, 5, 7, 9};
    cout << (lower_bound(a, a + 5, 1) - a) << endl;
    // 第一个大于等于1的元素是1,下标是0
    cout << (lower_bound(a, a + 5, 2) - a) << endl;
    // 第一个大于等于2的元素是3,下标是1
    cout << (lower_bound(a, a + 5, 8) - a) << endl;
    // 第一个大于等于8的元素是9,下标是4
    cout << (lower_bound(a, a + 5, 100) - a) << endl;
    // 最大的元素也不比100大,故返回值是last,再减a也就是5
}

自定义版本

#include <iostream>
#include <algorithm>
using namespace std;
struct point{
    point(){

    }
    point(int _x, int _y){
        x = _x;
        y = _y;
    }
    int x;
    int y;
};

bool cmp(point a, point b){
    return a.x < b.x;
}
int main(int argc, char *argv[]){
    point a[5];

    a[0].x = 1;
    a[0].y = 100;

    a[1].x = 100;
    a[1].y = 1;

    a[2].x = 30;
    a[2].y = 50;

    a[3].x = 25;
    a[3].y = 120;

    a[4].x = 301;
    a[4].y = 103;
    // 随便赋值
    sort(a, a + 5, cmp);
    // 先排序
    for (int i = 0; i < 5; i++){
        printf("a[%d].x = %d, a[%d].y = %d\n", i, a[i].x, i, a[i].y);
    }
    // 输出会发现他们按照x从小到大排序了
    cout << (lower_bound(a, a + 5, point(1, 1000), cmp) - a) << endl;
    // 第一个x值大于1的元素是(1, 100)这个元素,它的下标为0
    cout << (lower_bound(a, a + 5, point(101, 1000), cmp) - a) << endl;
    // 第一个x值大于101的元素是(301, 103)这个元素,它的下标为4
    cout << (lower_bound(a, a + 5, point(1000, 1000), cmp) - a) << endl;
    // 因为找不到所以返回a + 5,再减a就是5
    
}

upper_bound()

用法跟lower_bound()一样,只不过它返回的是第一个大于x的值的地址, 而lower_bound()是返回第一个大于等于x的值的地址,> 和 >= 是二者的区别

示例

#include <iostream>
#include <algorithm>
using namespace std;
int main(int argc, char *argv[]){
    int a[] = {1, 3, 5, 7, 9};
    cout << (upper_bound(a, a + 5, 1) - a) << endl;
    // 第一个大于1的元素是3,下标是1
    cout << (upper_bound(a, a + 5, 2) - a) << endl;
    // 第一个大于2的元素是3,下标是1
    cout << (upper_bound(a, a + 5, 7) - a) << endl;
    // 第一个大于7的元素是9,下标是4
    cout << (upper_bound(a, a + 5, 100) - a) << endl;
    // 最大的元素也不比100大,故返回值是last,再减a也就是5
}

如果要求第一个小于x的数,或者第一个小于等于x的数怎么办呢?

还是用上面两个函数就可以了

查找第一个小于等于x的数(注:这里的意思为小于x的数里最大的那个)

算法:upper_bound()的返回值 - 1,就是要查找的地址

比如数组是int a[] = {1, 3, 5, 7, 9}要查找的数x是3
用upper_bound()找到的是第一个大于3的数对吧,它的返回值是5的地址,把返回结果再减1就好了,就是3的地址了。第一个小于等于3的元素是3,没错吧!

这是刚好数组里有x的情况,那如果没有呢?比如要查找的元素是4,那upper_bound()的返回值是5的地址,再减1,就是3的地址了,第一个小于等于
4的元素是3,没错吧!

那如果查的元素比第一个元素还要小呢,比如-1,那upper_bound()的返回值是a,再减1就是a的前一个单元了。所以这里得特判了,要不然段错误了。

查找第一个小于x的数

算法:lower_bound()的返回值 - 1,就是要查找的地址

还是用上面的数据为例子
要查找的元素为7,lower_bound的返回值为7的地址,再减一就是5的地址,第一个小于7的元素是5,没错。
要查找8呢,lower_bound()返回的是9的地址,再减一就是7,没错。
查找-1,lower_bound()返回1的地址,也就是a,再减一为a的前一个单元,会越界,需要特判。

附:自己写的lower_bound版本

注意:我的下标从1开始,然后一定要注意,初始l = 1, r = n + 1,也就是说[l, r)是个左闭右开区间,r是没有访问元素的
ll是long long,代码前面有typedef,竞赛写习惯了

ll lower_bound(ll *a, ll x, ll n){
    ll l = 1, r = n + 1;
    while (l < r){
        ll mid = (l + r) / 2;
        if (x > a[mid]){
            l = mid + 1;
        }
        else if (x < a[mid]){
            r = mid;
        }
        else{
            return mid;
        }
    }
    return l;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 10,984评论 0 9
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 13,157评论 1 51
  • HTML 5 HTML5概述 因特网上的信息是以网页的形式展示给用户的,因此网页是网络信息传递的载体。网页文件是用...
    阿啊阿吖丁阅读 10,048评论 0 0
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 10,011评论 0 5
  • 一切都是钱惹的祸。 钱是人心靠近之本,也是人心背离之源,金钱可以影响人的心情,左右人的运势。有钱则奉趋者如林,没钱...
    臭小妈妈阅读 1,409评论 0 0

友情链接更多精彩内容