以前用这两个函数的时候,简单看了几句别人的博客,记住了大概,用的时候每用一次就弄混一次,相当难受,今天对照着这两个函数的源码和自己的尝试发现:其实这两个函数只能用于 “升序” 序列。

为什么还要加个引号呢?因为比较规则可以自定义,如果你非要把比较规则定义成 5 比 3 小,那么 降序序列也是可以用的,否则不可以,直接看下例子(这是升序序列的 ):

#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[] = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
cout << (lower_bound(a, a + 12, 4) - a) << endl; //输出 9
cout << (upper_bound(a, a + 12, 4) - a) << endl; //输出 12
cout << (lower_bound(a, a + 12, 1) - a) << endl; //输出 0
cout << (upper_bound(a, a + 12, 1) - a) << endl; //输出 3
cout << (lower_bound(a, a + 12, 3) - a) << endl; //输出 6
cout << (upper_bound(a, a + 12, 3) - a) << endl; //输出 9
cout << (lower_bound(a, a + 12, 5) - a) << endl; //输出 12
cout << (upper_bound(a, a + 12, 5) - a) << endl; //输出 12
cout << (lower_bound(a, a + 12, 0) - a) << endl; //输出 0
cout << (upper_bound(a, a + 12, 0) - a) << endl; //输出 0
return 0;
}

不出所料,在对 4 进行 lower_bound 时,输出结果是 9,因为在升序序列中 lower_bound 返回第一个大于等于 参数val 的 序列值的迭代器,这里 val 为 4,lower_bound 进行二分查找,找到第一个 4 时符合条件所以返回(确切的说当步长减到 0 时,欲返回的这个迭代器会停在第一个 4 那里),然后减去首迭代器 a,就是两个迭代器的距离了(在这里也就是数组中下标),第一个 4 的下标是 9。在对 4 进行 upper_bound 时,输出结果是 12,因为在升序序列中 upper_bound 返回第一个大于 参数val 的 序列值的迭代器,不幸的是这个序列里找不到大于 4 的值,所以迭代器走到尽头也没有找到,于是返回了一个尾迭代器(在这里是数组越界后的那一个元素的指针),它在数组中下标为 12 。同理可以对剩下的那几个分析。

那么如果是降序序列呢?如果是降序序列,这个函数仍然以为你这个序列是升序的,我们以{4,4,4,3,3,3,2,2,2,1,1,1}作为例子,试验一下。

#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[] = {4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1}; cout << (lower_bound(a, a + 12, 4) - a) << endl; // 输出 12
cout << (upper_bound(a, a + 12, 4) - a) << endl; // 输出 12
cout << (lower_bound(a, a + 12, 1) - a) << endl; // 输出 0
cout << (upper_bound(a, a + 12, 1) - a) << endl; // 输出 0
cout << (lower_bound(a, a + 12, 3) - a) << endl; // 输出 12
cout << (upper_bound(a, a + 12, 3) - a) << endl; // 输出 12 return 0;
}

不难发现,这两个函数的输出结果都很无厘头,不是期望的结果,那么为什么会这样呢?刚才说了,这个函数仍然以为你这个序列是升序的,以这句为例 lower_bound(a, a + 12, 4) ,因为是二分查找,第一步从中间开始,取中间值 a[(0+12)/2] = a[6] = 2 ,比 4 小,但是他想要找到第一个大于等于 4 的,所以继续向更大的值靠近,向哪边靠近呢,右边,因为他以为你这是升序的,所以取右半部分中间值 a[(7+12)/2] = a[9] = 1,比 4 小,所以继续向更大的值靠近,取右半部分中间值 a[(10+12)/2] = a[11] = 1,比 4 小,所以继续向更大的值靠近,取右半部分中间值 a[(12+12)/2] = a[12],到这不用取了,到头了,该返回了,所以最终返回了尾迭代器。

对照一下它的一个可能的实现源码,或许有助于理解。

这个 iterator_traits<ForwardIterator>::difference_type 其实就是个 int 类型,只是另起了一群其他名字,distance 函数是计算两个迭代器之间距离,advance 函数是将参数1(迭代器类型)前进 step 步,剩下的就没有什么不认识的东西了。

template <class ForwardIterator, class T>
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = distance(first, last);
while(count > 0)
{
it = first; step = count / 2;
advance(it, step);
if (*it < val) { // or: if (comp(*it,val)), for version (2)
first = ++it;
count -= step + 1;
}
else
count = step;
}
return first;
}

转载自:

--------------------- 

作者:锦夏挽秋 

来源:CSDN 

原文:https://blog.csdn.net/qq1337715208/article/details/81072709

lower_bound 和 upper_bound 功能和用法的更多相关文章

  1. 关于lower_bound( )和upper_bound( )的常见用法

    lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的. 在从小到大的排序数组中, lower_bound( begin,end,num):从数 ...

  2. lower_bound( )和upper_bound( )的常见用法

    lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的. 在从小到大的排序数组中, lower_bound( begin,end,num):从数 ...

  3. lower_bound( )和upper_bound( )的基本用法

    lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end.通过返回的地址减去起始地址 ...

  4. 关于lower_bound()和upper_bound()

    关于lower_bound()和upper_bound(): 参考:关于lower_bound( )和upper_bound( )的常见用法 注意:查找的数组必须要是排好序的.因为,它们查找的方式也是 ...

  5. lower_bound和upper_bound的实现和基本用法

    最近一直在学dp,但是感觉进度明显慢了很多,希望自己可以加一把劲,不要总是拖延了... 在LIS的优化中我遇到了二分查找的问题,之前也知道lower_bound和upper_bound两个函数,但是没 ...

  6. lower_bound()和upper_bound()用法详解

    lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的. lower_bound( begin,end,num):从数组的begin位置到end ...

  7. 【模板】关于vector的lower_bound和upper_bound以及vector基本用法 STL

    关于lower_bound和upper_bound 共同点 函数组成: 一个数组元素的地址(或者数组名来表示这个数组的首地址,用来表示这个数组的开头比较的元素的地址,不一定要是首地址,只是用于比较的& ...

  8. STL之std::set、std::map的lower_bound和upper_bound函数使用说明

    由于在使用std::map时感觉lower_bound和upper_bound函数了解不多,这里整理并记录下相关用法及功能. STL的map.multimap.set.multiset都有三个比较特殊 ...

  9. C++二分查找:lower_bound( )和upper_bound( )

    #include<algorithm>//头文件 //标准形式 lower_bound(int* first,int* last,val); upper_bound(int* first, ...

随机推荐

  1. 零元学Expression Design 4 - Chapter 6 教你如何在5分钟内做出文字立体感效果

    原文:零元学Expression Design 4 - Chapter 6 教你如何在5分钟内做出文字立体感效果 又来一篇五分钟做设计啦~ 本篇将教大家如何运用Design内建工具Blend Path ...

  2. Oltu在Jersey框架上实现oauth2.0授权模块

    oltu是一个开源的oauth2.0协议的实现,本人在此开源项目的基础上进行修改,实现一个自定义的oauth2.0模块. 关于oltu的使用大家可以看这里:http://oltu.apache.org ...

  3. python 教程 第十八章、 Web编程

    第十八章. Web编程 import urllib2 LOGIN = 'jin' PASSWD = 'Welcome' URL = 'https://tlv-tools-qc:8443/qcbin/s ...

  4. JSONObject 解析

    前解析json已使用get方法,但是,假设抛出将解决很烦人中断. 今天发现JSONObject还提供了一个更好用的方法opt.看来以后文档还是要更加认真的读的.以下是文档中的原文. A JSONObj ...

  5. Golang的演化历程

    本文来自Google的Golang语言设计者之一Rob Pike大神在GopherCon2014大会上的开幕主题演讲资料“Hello, Gophers!”.Rob大神在这次分 享中用了两个生动的例子讲 ...

  6. JS 中click和onclick的区别

    1.onclick是绑定事件,告诉浏览器在鼠标点击时候要做什么 2.click本身是方法,作用是触发onclick事件,只要执行了元素的click()方法,就会触发onclick事件

  7. Visual Studio更改编码格式为“UTF-8”

    原文:Visual Studio更改编码格式为"UTF-8" 用VS2015新建了个Python文件,在VS2015打开时中文显示正常, 用Visual Studio Code文本 ...

  8. dataGrid 源更新 事件

    DataGrid myGrid = new DataGrid(); CollectionView myCollectionView = (CollectionView)CollectionViewSo ...

  9. delphi资源文件的使用

    delphi资源文件的使用 资源文件(*.res)通过编译指令 $R 关联, 譬如工程文件 Project1 中的 {$R *.res} 就是关联 Project1.res 资源文件, 我们直接写作 ...

  10. Win10《芒果TV》更新v3.8.70周年版:升级高级配色、自动切换夜间模式

    官宣!光阴似箭,已过三年时光,我们一起从最初的青涩变成更加成熟起来,同呼吸共命运,匠心依旧,感恩有你,Win10版<芒果TV>全平台同步更新周年版v3.8.70,升级高级配色,新增自动切换 ...