二分查找—lower_bound 、upper_bound 、binary_search

2024-04-04 13:18

本文主要是介绍二分查找—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进行比较。

######################################################################

std::sort      对vector成员进行排序;

std::sort(v.begin(),v.end(),compare);

std::lower_bound 在排序的vector中进行二分查找,查找第一大于等于;
std::lower_bound(v.begin(),v.end(),v.element_type_obj,compare);

std::upper_bound 在排序的vector中进行二分查找,查找第一个大于;
std::upper_bound(v.begin(),v.end(),v.element_type_obj,compare);

std::binary_search 在排序的vector中进行二分查找;
std:: binary_search(v.begin(),v.end(),v.element_type_obj,compare );

std::unique 将排序的vector
vector<element_type>::iterator iter = std::unique(v.begin(),v.end(),compare);
v.resize(iter-v.begin());

std::for_each 将迭代器指向区间的内容调用指定的函数
void show(element_type& obj);
std::for_each(v.begin(),v.end(),show);
这里也可以:
strcut showclass
{
       void  operator ()(element_type& obj){
                 //具体操作......
       }
}showobj;
std::for_each(v.begin(),v.end(),showobj);

std::random_shuffle将迭代器指向的内容内容打散
std::random_shuffle(v.begin(),v.end());
或:
// random generator function:
ptrdiff_t myrandom (ptrdiff_t i) { return rand()%i;}
// pointer object to it:
ptrdiff_t (*p_myrandom)(ptrdiff_t) = myrandom;
random_shuffle ( myvector.begin(), myvector.end(), p_myrandom);

具体使用:
std::sort使用:
              std::sort(vectorobj.begin(),vectorobj.end(),compare_fun);
std:: lower_bound 使用:
      std:: lower_bound  ( vectorobj.begin(),vectorobj.end(),比较对象,compare_fun );
     比较对象的类型和vectorobj的成员类型一样。
示例:
#include <vector>
#include <algorithm>
#include <algorithm>
#include <iostream>
struct Student
{int age;
};
//sort和lower_bound使用比较函数的原型:
//boo function(const vector的成员类型 lit,const vector的成员类型 rit);
bool CompareOperation(const Student& lit,const Student& rit)     
{if(lit.age<rit.age){return true;}else{return false;}
}
int main(int argc,char *argv[])
{std::vector<Student> stuvec;Student a;a.age = 5;stuvec.push_back(a);Student b;b.age = 6;stuvec.push_back(b);Student c;c.age = 4;stuvec.push_back(c);Student d;d.age = 7;stuvec.push_back(d);std::cout<<"befort sort"<<std::endl;for(size_t index=0;index<stuvec.size();index++){std::cout<<stuvec[index].age<<std::endl;}std::sort(stuvec.begin(),stuvec.end(),CompareOperation);std::cout<<"after sort"<<std::endl;for(size_t index=0;index<stuvec.size();index++){std::cout<<stuvec[index].age<<std::endl;}std::cout<<"binary search"<<std::endl;std::vector<Student>::iterator iter = std::lower_bound(stuvec.begin(),stuvec.end(),b,CompareOperation);if(iter != stuvec.end()){std::cout<<iter->age<<std::endl;}return 0;
}
运行结果:
stl算法库参看:
http://www.cplusplus.com/reference/algorithm/lower_bound/?kw=lower_bound    >=    的第一个元素
http://www.cplusplus.com/reference/algorithm/upper_bound/?kw=upper_bound    >     的第一个元素
示例代码:
// lower_bound/upper_bound example
#include <iostream>     // std::cout
#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort
#include <vector>       // std::vector
int main () {int myints[] = {10,20,30,30,20,10,10,20};std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30std::vector<int>::iterator low,up;low=std::lower_bound (v.begin(), v.end(), 20); // 第一个   >= 20 的元素的迭代器up= std::upper_bound (v.begin(), v.end(), 20); // 第一个   > 20  的元素的迭代器  std::cout << "lower_bound at position " << (low- v.begin()) << '\n';std::cout << "upper_bound at position " << (up - v.begin()) << '\n';return 0;
}
// 使用std::unique可以将有序的vector中的成员去重:
#include <iostream>     // std::cout
#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort,std::unique, std::for_each
#include <vector>       // std::vector
void show(const int& i)
{std::cout<<i<<std::endl;
}
int main () {int myints[] = {10,20,30,30,20,10,10,20};std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30std::vector<int>::iterator iter = std::unique(v.begin(),v.end());v.resize(iter - v.begin());std::for_each(v.begin(),v.end(),show);return 0;
}
使用std::binary_search对vector进行排序;
// binary_search example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool myfunction (int i,int j) { return (i<j); }
int main () {int myints[] = {1,2,3,4,5,4,3,2,1};vector<int> v(myints,myints+9);                         // 1 2 3 4 5 4 3 2 1// using default comparison:sort (v.begin(), v.end());cout << "looking for a 3... ";if (binary_search (v.begin(), v.end(), 3))cout << "found!\n"; else cout << "not found.\n";// using myfunction as comp:sort (v.begin(), v.end(), myfunction);cout << "looking for a 6... ";if (binary_search (v.begin(), v.end(), 6, myfunction))cout << "found!\n"; else cout << "not found.\n";return 0;
}
参看:http://www.cplusplus.com/reference/algorithm/binary_search/?kw=binary_search
std::random_shuffle将指定的迭代器区间的内容随机打散:
// random_shuffle example
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;// random generator function:
ptrdiff_t myrandom (ptrdiff_t i) { return rand()%i;}// pointer object to it:
ptrdiff_t (*p_myrandom)(ptrdiff_t) = myrandom;int main () {srand ( unsigned ( time (NULL) ) );vector<int> myvector;vector<int>::iterator it;// set some values:for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9// using built-in random generator:random_shuffle ( myvector.begin(), myvector.end() );// using myrandom:random_shuffle ( myvector.begin(), myvector.end(), p_myrandom);// print out content:cout << "myvector contains:";for (it=myvector.begin(); it!=myvector.end(); ++it)cout << " " << *it;cout << endl;return 0;
}
###############################区间查找的实现######################################

void TransformIntoScheduleConfig(OS::CommonPolicy *timesetting,   ScheduleConfiguration *scheduleconfig) {OS::TimeRange *timerangesetting = NULL;ScheduleConfiguration::TimeRange timerange;ywb_uint32_t size = 0;ywb_uint32_t pos = 0;ywb_uint32_t hour = 0;ywb_uint32_t min = 0;string *time;string tmp;size = timesetting->time_range_size();for (ywb_uint32_t i = 0; i < size; i++) {timerangesetting = timesetting->mutable_time_range(i);time = timerangesetting->mutable_str_time(0);pos = time->find(':');tmp = time->substr(0, pos);hour = std::atoi(tmp.c_str());tmp = time->substr(pos + 1, time->size() - pos - 1);min = std::atoi(tmp.c_str());timerange.mStart = hour * 3600 + min * 60;time = timerangesetting->mutable_str_time(1);pos = time->find(':');tmp = time->substr(0, pos);hour = std::atoi(tmp.c_str());tmp = time->substr(pos + 1, time->size() - pos - 1);min = std::atoi(tmp.c_str());timerange.mEnd = hour * 3600 + min * 60;scheduleconfig->mRangeList.push_back(timerange);}scheduleconfig->mWeekDays = 0;size = timesetting->weekday_size();for (ywb_uint32_t i = 0; i < size; i++) {YWB_ASSERT(timesetting->weekday(i) >= 0);YWB_ASSERT(timesetting->weekday(i) <= 6);scheduleconfig->mWeekDays |= (0x01 << (7 - timesetting->weekday(i)));}
}
==============
ywb_bool_t TimeIsScheduled(ScheduleConfiguration *schedule)
{ywb_time_exp_t exptime;ywb_status_t err = YWB_SUCCESS;ywb_uint32_t seconds = 0;ScheduleConfiguration::TimeRange range;std::vector<ScheduleConfiguration::TimeRange>::iterator iter;err = ywb_time_exp_lt(&exptime, ywb_time_now());if (YWB_SUCCESS != err) {return ywb_true;}if (!((0x80 >> exptime.tm_wday) & schedule->mWeekDays)) {return ywb_false;}seconds = exptime.tm_hour*3600 + exptime.tm_min*60 + exptime.tm_sec;range.mStart = seconds;range.mEnd = seconds;iter = std::lower_bound(schedule->mRangeList.begin(), schedule->mRangeList.end(), range);if (schedule->mRangeList.end() == iter) {return ywb_false;}if (iter->mStart > seconds || iter->mEnd < seconds) {return ywb_false;}return ywb_true;
}
===============
class ScheduleConfiguration {
public:struct TimeRange{public:ywb_uint32_t mStart;ywb_uint32_t mEnd;public:bool operator<(const TimeRange &range){if(range.mStart == range.mEnd) {return mEnd < range.mEnd;} else {if(mStart == mEnd) {return mEnd <= range.mEnd;} else {return mEnd < range.mEnd;}}}};std::vector<TimeRange> mRangeList;ywb_uint8_t mWeekDays;public:void Copy(const ScheduleConfiguration &config){mWeekDays = config.mWeekDays;mRangeList.assign(config.mRangeList.begin(), config.mRangeList.end());}
};
=====================
/*** a structure similar to ANSI struct tm with the following differences:*  - tm_usec isn't an ANSI field*  - tm_gmtoff isn't an ANSI field (it's a bsdism)*/
struct ywb_time_exp_t {/** microseconds past tm_sec */ywb_int32_t tm_usec;/** (0-61) seconds past tm_min */ywb_int32_t tm_sec;/** (0-59) minutes past tm_hour */ywb_int32_t tm_min;/** (0-23) hours past midnight */ywb_int32_t tm_hour;/** (1-31) day of the month */ywb_int32_t tm_mday;/** (0-11) month of the year */ywb_int32_t tm_mon;/** year since 1900 */ywb_int32_t tm_year;/** (0-6) days since sunday */ywb_int32_t tm_wday;/** (0-365) days since jan 1 */ywb_int32_t tm_yday;/** daylight saving time */ywb_int32_t tm_isdst;/** seconds east of UTC */ywb_int32_t tm_gmtoff;
};

       具体分析见源码

//这是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 = 0;distance(first, last, len);	// 求取整个范围的长度,ForwardIterator没有-n操作Distance half;ForwardIterator middle;while (len > 0) {                        //为了跳出循环,而定义了len,如果用while(true) 然后每次判定长度在break,也行,不过没这个好half = len >> 1;			// 除以2,注意这种移位写法,不需编译器进行优化middle = first;			     // 这两行令middle 指向中间位置advance(middle, half);       //ForwardIterator没有+n的操作if (*middle < value) {		// 如果中间位置的元素值 < 标的值,value在后半区间first = middle;			// 这两行令 first 指向 middle 的下一位置++first;len = len - half - 1;		// 修正 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 = 0;distance(first, last, len);Distance half;ForwardIterator middle;while (len > 0) {half = len >> 1;middle = first;advance(middle, half);if (comp(*middle, value)) {first = middle;++first;len = len - half - 1;}elselen = 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 > 0) {
half = len >> 1;			
middle = first + half;		if (*middle < value) {		first = middle + 1;		len = len - half - 1;		//修正 len,回头测试循环条件,RamdonAccessIterator版本}elselen = 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 > 0) {half = len >> 1;middle = first + half;if (comp(*middle, value)) {first = middle + 1;len = len - half - 1;}elselen = 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 = 0;distance(first, last, len);	Distance half;ForwardIterator middle;while (len > 0) {half = len >> 1;			middle = first;			    advance(middle, half);if (value < *middle)		// 如果中间位置的元素值大于标的值,证明在前半部分len = half;				// 修正len
else {						// 注意如果元素值相等的话,那么是在后半部分找// 与lower_bound进行比较first = middle;			// 在下半部分,令first指向middle的下一个位置++first;len = len - half - 1;		// 修正 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 > 0) {half = len >> 1;			middle = first + half;		if (value < *middle)		len = half;				    else {first = middle + 1;		len = len - half - 1;		}}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 = 0;distance(first, last, len);Distance half;ForwardIterator middle;while (len > 0) {half = len >> 1;middle = first;advance(middle, half);if (comp(value, *middle))len = half;else {first = middle;++first;len = len - half - 1;}}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 > 0) {half = len >> 1;middle = first + half;if (comp(value, *middle))len = half;else {first = middle + 1;len = len - half - 1;}}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);
}


binary_search二分法怎样使用?

二分法检索又称折半检索,二分法检索的基本思想是设字典中的元素从小到大有序地存放在数组中,首先将给定值key与字典中间位置上元素的关键码比较,如果相等,则检索成功;否则,若key小,则在字典前半部分中继续进行二分法检索,若key大,则在字典后半部分中继续进行二分法检索。这样,经过一次比较就缩小一半的检索区间,如此进行下去,直到检索成功或检索失败。二分法检索是一种效率较高的检索方法,要求字典在顺序表中按关键码排序。

binary_search

原型:

 #include <algorithm>
 bool binary_search( forward_iterator start, forward_iterator end, const TYPE& val );
 bool binary_search( forward_iterator start, forward_iterator end, const TYPE& val, Comp f );

返回值:

true if an element is found in the range that is equal or equivalent to the specified value; otherwise, false.

代码演示:

#include <algorithm>

int main()
{
    int nums[] = { -242, -1, 0, 5, 8, 9, 11 };//必须按递增顺序排列
    int start = 0; int end = 7;  
    for( int i = 0; i < 10; i++ ) 
    {
        if( std::binary_search( nums+start, nums+end, i ) )//如果找到返回TRUE,没有找到则返回FALSE
        {
            printf("找到\n");
        }
        else 
        {
            printf("没找到\n");
        }
    }
    return 0;
}

附注1:数组必须是按递增顺序排列的,否则错误

更详细的可参考MSDN,以及上面所列举的一个例子


这篇关于二分查找—lower_bound 、upper_bound 、binary_search的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/875873

相关文章

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

uva 575 Skew Binary(位运算)

求第一个以(2^(k+1)-1)为进制的数。 数据不大,可以直接搞。 代码: #include <stdio.h>#include <string.h>const int maxn = 100 + 5;int main(){char num[maxn];while (scanf("%s", num) == 1){if (num[0] == '0')break;int len =

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

poj 3104 二分答案

题意: n件湿度为num的衣服,每秒钟自己可以蒸发掉1个湿度。 然而如果使用了暖炉,每秒可以烧掉k个湿度,但不计算蒸发了。 现在问这么多的衣服,怎么烧事件最短。 解析: 二分答案咯。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <c

poj 3258 二分最小值最大

题意: 有一些石头排成一条线,第一个和最后一个不能去掉。 其余的共可以去掉m块,要使去掉后石头间距的最小值最大。 解析: 二分石头,最小值最大。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <c

poj 2594 二分图最大独立集

题意: 求一张图的最大独立集,这题不同的地方在于,间接相邻的点也可以有一条边,所以用floyd来把间接相邻的边也连起来。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <sta

poj 3692 二分图最大独立集

题意: 幼儿园里,有G个女生和B个男生。 他们中间有女生和女生认识,男生男生认识,也有男生和女生认识的。 现在要选出一些人,使得这里面的人都认识,问最多能选多少人。 解析: 反过来建边,将不认识的男生和女生相连,然后求一个二分图的最大独立集就行了。 下图很直观: 点击打开链接 原图: 现图: 、 代码: #pragma comment(

poj 2112 网络流+二分

题意: k台挤奶机,c头牛,每台挤奶机可以挤m头牛。 现在给出每只牛到挤奶机的距离矩阵,求最小化牛的最大路程。 解析: 最大值最小化,最小值最大化,用二分来做。 先求出两点之间的最短距离。 然后二分匹配牛到挤奶机的最大路程,匹配中的判断是在这个最大路程下,是否牛的数量达到c只。 如何求牛的数量呢,用网络流来做。 从源点到牛引一条容量为1的边,然后挤奶机到汇点引一条容量为m的边

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter