二分查找函数只能用于已经排好序的数组。
二分法可以理解为:猜数<100的范围内,优先考虑50,其次75。诸如此类。
lower_bound函数
语法格式
lower_bound(起始函数,终止函数,要查找的值);
功能说明
用于在指定区域内查找不小于目标值的第一个元素。返回值为目标值所在的位置,如果没有找到,则返回值为终止位置。
注意,使用该函数在指定范围内查找某个目标值时,最终查找到的不一定是和目标值相等的元素,还可能是比目标值大的元素。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[1000005];//定义数组时一旦超过1000000,就要放在main之前!
int main(int argc,char*argv[])
{
int n,m,i,x;
cin>>n>>m;
for(i=0;i<=n-1;i++) {
scanf("%d",&a[i]);
}
for(i=1;i<=m;i++){
cin>>x;
int *p=lower_bound(a,a+n,x);
//查找第一个目标值的值,有可能等于也有可能大于,但只要没有一定指最后。
if(*p==x) printf("%d ",p-a+1);//判断p的位置存储的值正好等于x。
//定义时用*,表示此位置上的数值也要用*。
//也可以用a[p-a]代替*p,表示此位置数值。
else printf("-1 ");
}
return 0;
}
upper_bound函数
语法格式
upper_bound(起始位置,终止位置, 要查找的值);
功能说明
用于在指定范围内查找大于目标值的第一个元素。返回值为目标值所在的位置,如果没有找到,则返回值为终止位置。
#include<bits/stdc++.h>
using namespace std;
long a[200001];
long N,C,ans;
int main()
{
cin>>N>>C;
for(int i=1;i<=N;i++)
{
cin>>a[i];
}
sort(a+1,a+N+1);//排序,方便使用lower_bound和upper_bound。
for(int i=1;i<=N;i++)
{
ans+=((upper_bound(a+1,a+N+1,a[i]+C)-a)-(lower_bound(a+1,a+N+1,a[i]+C)-a));
}
cout<<ans;
return 0;
}
二分法的手写代码
这种查找方法每次取中点位置上的数据进行比较,根据比较结果将查找区间缩小为初始区间的二分之一,故称二分查找法。
设数组a具有N个元素,存储于数组元素a[0]-a[N-1]中,并且已升序排序,那么如果要在数组中查找指定值x,则可以使用如下的算法:
step1:设左边界L=0,右边界R=N-1;
step2:如果L>R,则在数组a中未找到指定值x,查找结束,转step7,否则转step3;
setp3:计算中点值M=(L+R)/2;
step4:如果a[M]==x,则在位置M找到指定值,转step7;
step5:如果a[M]>x,则查找的数据x位于数组左半段,赋值R=M-1,转step2;
step6:如果a[M]<x,则查找的数据x位于数组右半段,赋值L=M+1,转step2;
step7:查找结束,输出结果。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[1000005];
int main(int argc,char*argv[])
{
int n,m,i,x;
cin>>n>>m;
for(i=0;i<=n-1;i++) scanf("%d",&a[i]);
for(i=1;i<=m;i++){
cin>>x;
int L=0,R=n-1,M;
while(L<=R)//while(1)是死循环,非零就是真,条件是真就死循环
{
M=(L+R)/2;//计算中点
if(a[M]==x) break;
if(a[M]>x) R=M-1;//右边界向左移
if(a[M]<x) L=M+1;//左边界向右移
}
if(L<=R) {
while(a[M-1]==x && M>0) M--;//如果前一个等于,再向前推一个。同时注意下标从0开始减后不能为负。
//程序可能推很多次,所以会导致TLE。
printf("%d ",M+1);
}
else printf("-1 ");
}
return 0;
}
(以上代码目前还是TLE。。。)
更正后代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef struct Node node;
int main(int argc,char*argv[])
{
int a[11]={1,2,3,4,4,4,5,6,9,12,34};
int x=4,n=11;
int L=0,R=n-1,M;
while(L<R){
M=(L+R)/2;
// if(a[M]==x) break;//没有break了。
if(a[M]<x) L=M+1;
if(a[M]>=x) R=M;//很有可能此时的x是第一个,所以不能减一。
}
if(a[L]==x) printf("%d\n",L+1);//a[L]=x时就找到了。
else printf("%d\n",-1);
return 0;
}
同理可以查找最后位置。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef struct Node node;
int main(int argc,char*argv[])
{
int a[11]={1,2,3,4,4,4,5,6,9,12,34};
int x=4,n=11;
int L=0,R=n-1,M;
while(L<R){
M=(L+R)/2;//注意要考虑向上取整!!!否则会导致死循环。因此。。。
if(M*2!=L+R) M++;//如果能整除直接出结果,不能整除才加一。
if(a[M]<=x) L=M;
if(a[M]>x) R=M-1;
}
if(a[L]==x) printf("%d\n",L+1);
else printf("%d\n",-1);
return 0;
}