二分查找 Binary Search

二分查找也称折半查找(Binary Search),相对于普通的顺序查找,二分查找具有极好的效率。

使用条件:要求线性表必须采用 顺序存储结构 ,而且表中元素按关键字 有序排列

时间复杂度:$ \Theta(logn) $

查找过程:

首先,假设表中元素是按升序排列。

将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;

否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。

重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

手写二分查找

int Binary_search(int x,int from,int to)
{
	int l=from,r=to,mid=0;
    //a数组是升序,查找区间从from开始,到to结束。
	while(l<=r)
    {
		int mid=l+( (r-l)>>1 );/*注*/
			if(a[mid]>x)//中值大于所求值,所求值在左边。 
				r=mid-1;
			else if(a[mid]<x)//中值小于于所求值,所求值在右边。
				l=mid+1;
			else
				return mid;
	}
    return -1;
    //找不到返回-1.
} 

注:

使用$ (l+r)/2$ 或是 $l+r>>1 \(会有**整数溢出的问题**。 即:\)l+r$ 的结果有可能大于表达式结果类型所能表示的最大值,
这样,产生溢出后再/2是不会产生正确结果的,而 \(l+(r-l)/2\)
不存在这个问题。

关于二分查找的两个 STL 模板:

binary_search:二分查找函数。一般格式:(开始位置,结束位置,要找的元素)。如果能找到,返回"true",否则,返回"false"。

lower_bound:前者只能判断数是否存在。并不能返回数的位置。lower_bound,找出第一个大于等于指定数的位置(迭代器)。如果没有找到,返回最后一个数据的后一个位置。

测评地址:P2249 【深基13.例1】查找

手写:

#include <bits/stdc++.h>
#define MAXN 1000005
int a[MAXN];
int main()
{
	int n,m;	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)	scanf("%d",&a[i]);
	for(int i=1;i<=m;++i)
	{
		int l=1,r=n,x;	scanf("%d",&x);
		//二分部分 
		while(r>=l)//= //=即 子区间还有一个。
		{
			int mid=l+( (r-l)>>1 );//(l+r)/2
            /*注1*/
			if(a[mid]<x)l=mid+1; 
			else r=mid-1;
            //这里从题目而言,是为了保证是第一个出现的位置。
            //所以说如果是a[mid] == x,那么,它会继续往左压,保证是第一个出现。
		}
		if(a[l]==x)	printf("%d ",l);
		//l或r都可以 
		else printf("-1 ");
	}
	return 0;
}

STL模板:

#include <bits/stdc++.h>
#define MAXN 1000005
int a[MAXN];
int main()
{
	int n,m;	std::scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)	std::scanf("%d",&a[i]);
	for(int i=1;i<=m;++i)
	{
		int x;	std::scanf("%d",&x);
		int j=std::lower_bound(a+1,a+n+1,x)-a;
		//指针减,得到下标 
		if(a[j]!=x)	std::printf("-1 ");
		else std::printf("%d ",j);
	}
	return 0;
}

手写二分的测评结果:
awHsSK.png
lower_bound的测评结果:
awHDW6.png

对比可以看出,手写二分的时间是略快于lower_bound的。说明lower_bound的时间复杂度常数较大。

但lower_bound的代码相对于手写二分简单。两者各有利弊。

做题感悟:

  • 题目中常常出现的是运用二分查找的思想,灵活变通的运用二分,并不是简简单单的查找数值,所以要熟练的掌握手写二分。
posted @ 2020-08-04 11:44  x_miracle  阅读(140)  评论(0编辑  收藏  举报