本篇文章同步发表于 luogu-blog
两个函数用于 升序 降序 非递减序列(升序带并列),非递增序列(降序带并列)
这两个函数都是STL自带的二分查找函数,具有优秀的时间复杂度(O(logn))
在头文件<algorithm>
内,不过lower_bound
不用<algorithm>
好像不会报错。(逃~)
函数原型
_ForwardIterator lower_bound(_ForwardIterator _first,_ForwardIterator _last,const _Tp&__val)
_ForwardIterator upper_bound(_ForwardIterator _first,_ForwardIterator _last,const _Tp&__val)
升序(带并列)
lower_bound()
和upper_bound()
默认在升序序列中进行二分查找,不需要添加参数。
lower_bound()
在一个升序序列中,返回一个指向大于等于该元素的第一个迭代器。
如果没有大于等于该元素的元素,返回指向最后一位元素的后一位的迭代器,即last
,注意last
是越界的!
#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
int num[]={0,1,1,2,3,6,7,9,15,17,21,32,48}; //升序
const int n=12;
int main()
{
cout<<num[(lower_bound(num+1,num+n+1,8)-num)]<<endl; //result : 9
//两种写法相同
cout<<*lower_bound(num+1,num+n+1,0)<<endl; //result : 1
cout<<*lower_bound(num+1,num+n+1,1)<<endl; //result : 1
cout<<*lower_bound(num+1,num+n+1,2)<<endl; //result : 2
cout<<*lower_bound(num+1,num+n+1,3)<<endl; //result : 3
cout<<*lower_bound(num+1,num+n+1,4)<<endl; //result : 6
cout<<*lower_bound(num+1,num+n+1,5)<<endl; //result : 6
cout<<*lower_bound(num+1,num+n+1,6)<<endl; //result : 6
cout<<*lower_bound(num+1,num+n+1,7)<<endl; //result : 7
cout<<*lower_bound(num+1,num+n+1,8)<<endl; //result : 9
cout<<*lower_bound(num+1,num+n+1,9)<<endl; //result : 9
cout<<*lower_bound(num+1,num+n+1,10)<<endl; //result : 15
cout<<*lower_bound(num+1,num+n+1,15)<<endl; //result : 15
cout<<*lower_bound(num+1,num+n+1,17)<<endl; //result : 17
cout<<*lower_bound(num+1,num+n+1,22)<<endl; //result : 32
cout<<*lower_bound(num+1,num+n+1,49)<<endl; //result : 0
if(lower_bound(num+1,num+n+1,49)==num+n+1)
puts("lower_bound(num+1,num+n+1,49)==num+n+1");
//result:lower_bound(num+1,num+n+1,49)==num+n+1
//lower_bound()在一个升序序列中,返回一个指向大于等于该元素的第一个迭代器。
//如果没有大于等于该元素的元素,返回指向最后一位元素的后一位的迭代器;
return 0;
}
upper_bound()
在一个升序序列中,返回一个指向大于该元素的第一个迭代器。
如果没有大于该元素的元素,返回指向最后一位元素的后一位的迭代器;
#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int num[]={0,1,1,2,3,6,7,9,15,17,21,32,48}; //升序
const int n=12;
int main()
{
cout<<num[upper_bound(num+1,num+n+1,8)-num]<<endl; //result :9
//两种写法相同
cout<<*upper_bound(num+1,num+n+1,0)<<endl; //result :1
cout<<*upper_bound(num+1,num+n+1,1)<<endl; //result :2
cout<<*upper_bound(num+1,num+n+1,2)<<endl; //result :3
cout<<*upper_bound(num+1,num+n+1,3)<<endl; //result :6
cout<<*upper_bound(num+1,num+n+1,4)<<endl; //result :6
cout<<*upper_bound(num+1,num+n+1,5)<<endl; //result :6
cout<<*upper_bound(num+1,num+n+1,6)<<endl; //result :7
cout<<*upper_bound(num+1,num+n+1,7)<<endl; //result :9
cout<<*upper_bound(num+1,num+n+1,8)<<endl; //result :9
cout<<*upper_bound(num+1,num+n+1,9)<<endl; //result :15
cout<<*upper_bound(num+1,num+n+1,16)<<endl; //result :17
cout<<*upper_bound(num+1,num+n+1,25)<<endl; //result :32
cout<<*upper_bound(num+1,num+n+1,32)<<endl; //result :48
cout<<*upper_bound(num+1,num+n+1,49)<<endl; //result :0
if(upper_bound(num+1,num+n+1,48)==num+n+1)
puts("upper_bound(num+1,num+n+1,48)==num+n+1");
//result:upper_bound(num+1,num+n+1,48)==num+n+1
//upper_bound()在一个升序序列中,返回一个指向大于该元素的第一个迭代器。
//如果没有大于该元素的元素,返回指向最后一位元素的后一位的迭代器;
return 0;
}
降序(带并列)
降序查找需要加一个参数。
比如在int
类型的降序数列里查找。
bool cmp(const int &a,const int &b)
{
return a>b;
}
类似sort
,
在升序内用小于号,降序内用大于号。
感性理解:就是前一个数和后一个数的关系啦。。
lower_bound(num,num+n,1,cmp)
当然也可以用STL
自带的greater
lower_bound(num,num+n,1,greater<int>())
其他与升序一样。
upper_bound()
和lower_bound()
一样。
#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int num[]={48,32,21,17,15,9,7,6,3,2,1,1}; //降序
const int n=12;
bool cmp(const int &a,const int &b)
{
return a>b;
}
int main()
{
freopen(".out","w",stdout);
cout<<*lower_bound(num,num+n,1,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,1,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,2,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,3,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,4,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,5,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,6,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,7,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,8,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,9,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,10,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,15,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,17,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,22,greater<int>())<<endl;
cout<<*lower_bound(num,num+n,49,greater<int>())<<endl;
return 0;
}
(result)
1
1
2
3
3
3
6
7
7
9
9
15
17
21
48
结构体
竟然加入了可供(DIY)的参数,那就可以在一个结构体数组内实现二分查找了!
#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
struct student
{
int mark;
int num;
};
student a[20];
bool cmp(const student &a,const student &b)
{
return a.mark>b.mark;
}
int main()
{
a[0]=student{100,0};
a[1]=student{89,1};
a[2]=student{89,2};
a[3]=student{79,3};
a[4]=student{69,4};
a[5]=student{59,5};
a[6]=student{49,6};
a[7]=student{39,7};
a[8]=student{29,8};
a[9]=student{19,9};
a[10]=student{9,10};
student b={67,9};
cout<<lower_bound(a,a+10,b,cmp)->mark<<endl;
return 0;
}
(result)
59
特别鸣谢:热心网友之江学院石洗凡老师的帮助