STL lower_bound upper_bound binary-search
STL中的二分查找——lower_bound 、upper_bound 、binary_search
二分查找很简单,原理就不说了。STL中关于二分查找的函数有三个lower_bound 、upper_bound 、binary_search 。这三个函数都运用于有序区间(当然这也是运用二分查找的前提)。
其中如果寻找的value存在,那么lower_bound返回一个迭代器指向其中第一个这个元素。upper_bound返回一个迭代器指向其中最后一个这个元素的下一个位置(明确点说就是返回在不破坏顺序的情况下,可插入value的最后一个位置)。如果寻找的value不存在,那么lower_bound和upper_bound都返回“假设这样的元素存在时应该出现的位置”。要指出的是lower_bound和upper_bound在源码中只是变换了if—else语句判定条件的顺序,就产生了最终迭代器位置不同的效果。
binary_search试图在已排序的[first,last)中寻找元素value,若存在就返回true,若不存在则返回false。返回单纯的布尔值也许不能满足需求,而lower_bound、upper_bound能提供额外的信息。事实上由源码可知binary_search便是利用lower_bound求出元素应该出现的位置,然后再比较该位置 的值与value的值。该函数有两个版本一个是operator< ,另外一个是利用仿函数comp进行比较。
具体分析见源码:
- //这是forward版本
- template <class ForwardIterator, class T>
- inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
- const T& value) {
- return __lower_bound(first, last, value, distance_type(first),
- iterator_category(first));
- }
- // 这是版本一的 forward_iterator 版本
- template <class ForwardIterator, class T, class Distance>
- ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
- const T& value, Distance*,
- forward_iterator_tag) {
- Distance len = ;
- distance(first, last, len); // 求取整个范围的长度,ForwardIterator没有-n操作
- Distance half;
- ForwardIterator middle;
- while (len > ) { //为了跳出循环,而定义了len,如果用while(true) 然后每次判定长度在break,也行,不过没这个好
- half = len >> ; // 除以2,注意这种移位写法,不需编译器进行优化
- middle = first; // 这两行令middle 指向中间位置
- advance(middle, half); //ForwardIterator没有+n的操作
- if (*middle < value) { // 如果中间位置的元素值 < 标的值,value在后半区间
- first = middle; // 这两行令 first 指向 middle 的下一位置
- ++first;
- len = len - half - ; // 修正 len,回头测试循环条件
- }
- else // 注意如果是相等的话,那么执行的是else语句,在前半部分找
- // 与opper_bound进行比较
- len = half; // 修正 len,回头测试循环条件
- }
- return first;
- }
- // 这是带comp反函数的 forward_iterator 版本
- template <class ForwardIterator, class T, class Compare, class Distance>
- ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
- const T& value, Compare comp, Distance*,
- forward_iterator_tag) {
- Distance len = ;
- distance(first, last, len);
- Distance half;
- ForwardIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first;
- advance(middle, half);
- if (comp(*middle, value)) {
- first = middle;
- ++first;
- len = len - half - ;
- }
- else
- len = half;
- }
- return first;
- }
- // 这是random_access_iterator版本
- template <class ForwardIterator, class T, class Compare>
- inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
- const T& value, Compare comp) {
- return __lower_bound(first, last, value, comp, distance_type(first),
- iterator_category(first));
- }
- // 这是版本一的 random_access_iterator 版本
- template <class RandomAccessIterator, class T, class Distance>
- RandomAccessIterator __lower_bound(RandomAccessIterator first,
- RandomAccessIterator last, const T& value,
- Distance*, random_access_iterator_tag) {
- Distance len = last - first; //求取整个范围的长度,与ForwarIterator版本进行比较
- Distance half;
- RandomAccessIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first + half;
- if (*middle < value) {
- first = middle + ;
- len = len - half - ; //修正 len,回头测试循环条件,RamdonAccessIterator版本
- }
- else
- len = half;
- }
- return first;
- }
- //这是带comp仿函数 random_access_iterator 版本
- template <class RandomAccessIterator, class T, class Compare, class Distance>
- RandomAccessIterator __lower_bound(RandomAccessIterator first,
- RandomAccessIterator last,
- const T& value, Compare comp, Distance*,
- random_access_iterator_tag) {
- Distance len = last - first;
- Distance half;
- RandomAccessIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first + half;
- if (comp(*middle, value)) {
- first = middle + ;
- len = len - half - ;
- }
- else
- len = half;
- }
- return first;
- }
- // 这是forward_iterator版本
- template <class ForwardIterator, class T>
- inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
- const T& value) {
- return __upper_bound(first, last, value, distance_type(first),
- iterator_category(first));
- }
- // 这是版本一的 forward_iterator 版本
- template <class ForwardIterator, class T, class Distance>
- ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
- const T& value, Distance*,
- forward_iterator_tag) {
- Distance len = ;
- distance(first, last, len);
- Distance half;
- ForwardIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first;
- advance(middle, half);
- if (value < *middle) // 如果中间位置的元素值大于标的值,证明在前半部分
- len = half; // 修正len
- else { // 注意如果元素值相等的话,那么是在后半部分找
- // 与lower_bound进行比较
- first = middle; // 在下半部分,令first指向middle的下一个位置
- ++first;
- len = len - half - ; // 修正 len
- }
- }
- return first;
- }
- // 这是版本一的 random_access_iterator 版本
- template <class RandomAccessIterator, class T, class Distance>
- RandomAccessIterator __upper_bound(RandomAccessIterator first,
- RandomAccessIterator last, const T& value,
- Distance*, random_access_iterator_tag) {
- Distance len = last - first;
- Distance half;
- RandomAccessIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first + half;
- if (value < *middle)
- len = half;
- else {
- first = middle + ;
- len = len - half - ;
- }
- }
- return first;
- }
- // 这是带comp的版本
- template <class ForwardIterator, class T, class Compare>
- inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
- const T& value, Compare comp) {
- return __upper_bound(first, last, value, comp, distance_type(first),
- iterator_category(first));
- }
- // 这是带comp的 forward_iterator 版本
- template <class ForwardIterator, class T, class Compare, class Distance>
- ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
- const T& value, Compare comp, Distance*,
- forward_iterator_tag) {
- Distance len = ;
- distance(first, last, len);
- Distance half;
- ForwardIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first;
- advance(middle, half);
- if (comp(value, *middle))
- len = half;
- else {
- first = middle;
- ++first;
- len = len - half - ;
- }
- }
- return first;
- }
- // 这是带comp的 random_access_iterator 版本
- template <class RandomAccessIterator, class T, class Compare, class Distance>
- RandomAccessIterator __upper_bound(RandomAccessIterator first,
- RandomAccessIterator last,
- const T& value, Compare comp, Distance*,
- random_access_iterator_tag) {
- Distance len = last - first;
- Distance half;
- RandomAccessIterator middle;
- while (len > ) {
- half = len >> ;
- middle = first + half;
- if (comp(value, *middle))
- len = half;
- else {
- first = middle + ;
- len = len - half - ;
- }
- }
- return first;
- }
- // 版本一
- template <class ForwardIterator, class T>
- bool binary_search(ForwardIterator first, ForwardIterator last,
- const T& value) {
- ForwardIterator i = lower_bound(first, last, value);
- //这里的实现就是调用的lower_bound ,并且如果元素不存在那么lower_bound指向的元素一定是
- //operator < 为ture的地方。
- return i != last && !(value < *i);
- }
- // 版本二
- template <class ForwardIterator, class T, class Compare>
- bool binary_search(ForwardIterator first, ForwardIterator last, const T& value,
- Compare comp) {
- ForwardIterator i = lower_bound(first, last, value, comp);
- return i != last && !comp(value, *i);
- }
函数lower_bound(first , last , val)在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置
举例如下:
一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标
则
pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
所以,要记住:函数lower_bound(first , last , val)在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
测试代码如下:
- #include <iostream>
- #include <algorithm>
- #include <functional>
- #include <vector>
- using namespace std;
- int main()
- {
- const int VECTOR_SIZE = ;
- // Define a template class vector of int
- typedef vector<int > IntVector ;
- //Define an iterator for template class vector of strings
- typedef IntVector::iterator IntVectorIt ;
- IntVector Numbers(VECTOR_SIZE) ;
- IntVectorIt start, end, it, location ;
- // Initialize vector Numbers
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- start = Numbers.begin() ; // location of first
- // element of Numbers
- end = Numbers.end() ; // one past the location
- // last element of Numbers
- // print content of Numbers
- cout << "Numbers { " ;
- for(it = start; it != end; it++)
- cout << *it << " " ;
- cout << " }\n" << endl ;
- // return the first location at which 10 can be inserted
- // in Numbers
- location = lower_bound(start, end, ) ;
- cout << "First location element 10 can be inserted in Numbers is: "
- << location - start<< endl ;
- }
函数upper_bound(first , last , val)返回的在前闭后开区间查找的关键字的上界,如一个数组number序列1,2,2,4.upper_bound(2)后,返回的位置是3(下标)也就是4所在的位置,同样,如果插入元素大于数组中全部元素,返回的是last。(注意:此时数组下标越界!!)
返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置
测试代码如下:
- #include <iostream>
- #include <algorithm>
- #include <functional>
- #include <vector>
- using namespace std;
- void main()
- {
- const int VECTOR_SIZE = ;
- // Define a template class vector of int
- typedef vector<int, allocator<int> > IntVector ;
- //Define an iterator for template class vector of strings
- typedef IntVector::iterator IntVectorIt ;
- IntVector Numbers(VECTOR_SIZE) ;
- IntVectorIt start, end, it, location, location1;
- // Initialize vector Numbers
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- Numbers[] = ;
- start = Numbers.begin() ; // location of first
- // element of Numbers
- end = Numbers.end() ; // one past the location
- // last element of Numbers
- // print content of Numbers
- cout << "Numbers { " ;
- for(it = start; it != end; it++)
- cout << *it << " " ;
- cout << " }\n" << endl ;
- //return the last location at which 10 can be inserted
- // in Numbers
- location = lower_bound(start, end, ) ;
- location1 = upper_bound(start, end, ) ;
- cout << "Element 10 can be inserted at index "
- << location - start<< endl ;
- cout << "Element 10 can be inserted at index "
- << location1 - start<< endl ;
- }
STL lower_bound upper_bound binary-search的更多相关文章
- [STL]lower_bound&upper_bound
源码 lower_bound template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardI ...
- C++ STL中的Binary search(二分查找)
这篇博客转自爱国师哥,这里给出连接https://www.cnblogs.com/aiguona/p/7281856.html 一.解释 以前遇到二分的题目都是手动实现二分,不得不说错误比较多,关于返 ...
- STL模板整理 Binary search(二分查找)
前言: 之前做题二分都是手动二分造轮子,用起来总是差强人意,后来看到STL才发现前辈们早就把轮子造好了,不得不说比自己手动实现好多了. 常用操作 1.头文件 #include <algorith ...
- stl lower_bound upper_bound binary_search equal_range
自己按照stl实现了一个: http://www.cplusplus.com/reference/algorithm/binary_search/ 这里有个注释,如何判断两个元素相同: Two e ...
- 鬼知道是啥系列之——STL(lower_bound(),upper_bound() )
引子,不明觉厉: 百度,渐入佳境: 头铁,入门到放弃: lower_bound(): 头文件: #include<algorithm>函数功能: 函数lower_bound()在f ...
- STL lower_bound upper_bound 用法
1.lower_bound(begin,end,x) 返回第一个>=x的位置,找不到return .end() 2.upper_bound (begin,end,x) 返回第一个>x的位置 ...
- algorithm@ lower_bound implementation(Binary Search)
一道来自jhu algorithm的作业题: Given two sorted arrays A, B, give a linear time algorithm that finds two entr ...
- [转]C++ STL中的Binary search(二分查找)
链接地址:https://www.cnblogs.com/wkfvawl/p/9475939.html
- 【转】STL之二分查找 (Binary search in STL)
Section I正确区分不同的查找算法count,find,binary_search,lower_bound,upper_bound,equal_range 本文是对Effective STL第4 ...
随机推荐
- Python For Data Analysis -- Pandas
首先pandas的作者就是这本书的作者 对于Numpy,我们处理的对象是矩阵 pandas是基于numpy进行封装的,pandas的处理对象是二维表(tabular, spreadsheet-like ...
- C#编程总结(四)多线程应用(进度条的编程问题)——转自http://www.cnblogs.com/yank/p/3232955.html
多线程应用 多线程应用很广泛,简单总结了一下: 1)不阻断主线程,实现即时响应,由后台线程完成特定操作2)多个线程,完成同类任务,提高并发性能3)一个任务有多个独立的步骤,多个线程并发执行各子任务,提 ...
- Excel VBA
=COUNTIF(Y3:Y212,"=11") =SUMIF(Y3:Y212,"=11",AA3:AA212) =SUMPRODUCT((Y3:Y212=&qu ...
- Redis学习笔记--五种数据类型的使用场景
String 1.String 常用命令: 除了get.set.incr.decr mget等操作外,Redis还提供了下面一些操作: 获取字符串长度 往字符串append内容 设置和获取字符串的某一 ...
- Qt Model/View(官方翻译,图文并茂)
http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mode ...
- mvc EF 数据保存时,报错:”对一个或多个实体的验证失败……“之解决
在EF5.0添加实体数据到数据库的时候,出现“对一个或多个实体的验证失败.有关详细信息,请参见“EntityValidationErrors”属性这个错误 解决: SaveChanges前先关闭验证实 ...
- frameset、frame、noframes和iframe的区别
原网站地址:http://nmyun.blog.51cto.com/448726/155268 ■ 框架概念 :所谓框架便是网页画面分成几个框窗,同时取得多个 URL.只需要 <frameset ...
- SQL PROMPT 取消dbo前缀
SQL Prompt 无疑大大提高了开发者的效率,高效而简单,特别适合大型的数据库脚本编写,但遗憾得是至今没有可供使用的中文版本.SQL Prompt 默认对象名前面会有 dbo 前缀,在一些场合这样 ...
- Linq世界走一走
什么是Linq?它是用来做什么的?怎么用? Linq的优点是不管数据源是什么,都可以统一查询.换言之,它是一种包含一套标准查询操作符的查询语言,可以对多个数据源进行查询 ⑴Linq俗称语言集成查询(L ...
- sql Server 使某一列的值等于行号
declare @i INT update 表名 SET [列名]=@i,@i=@i+ WHERE 条件