二分查找函数【必考】

二分查找函数只能用于已经排好序的数组。

二分法可以理解为:猜数<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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值