模板 二分查找

整数二分:

整数二分是通过不断用中间的数与要查询的数进行比较进而来缩小区间,直到区间长度为1。
1.

若find存在于这个数组中返回从左往右数第一个等于这个数的下标,若不存在于这个数组中则返回从左往右数第一个 >= find 的数的下标

	int binary_search(int a[],int n,int find)
	{
		int l = 0,r = n-1;
		while(l < r)
		{
			int mid = l + r >> 1;
			if(a[mid] >= find)
				r = mid;
			else
				l = mid + 1;
		}
		return l;
	}

例如 在 1 3 3 7 9 中找 3 ,将会返回 1 (下标),找 4 则会返回 3 (对应7),找 2 则会返回 1 (对应第一个3),如果find不在1-9这个范围,则返回离他近的下标。

返回从左往右第一个符合条件的下标 模板:
[l , r] 区间被划分成 [l , mid] , [mid + 1 , r]

int binary_search(int a[],int n,int find)
	{
		int l = 0,r = n-1;
		while(l < r)
		{
			int mid = l + r >> 1;
			if(测试条件)
				r = mid;
			else
				l = mid + 1;
		}
		return l;
	}

2.

若find存在于这个数组中返回从右往左数第一个等于这个数的下标,若不存在于这个数组中则返回从右往左数第一个 <= find 的数的下标

	int binary_search(int a[],int n,int find)
	{
			int l = 0,r = n-1;
			while(l < r)
			{
				int mid = l + r +1 >> 1;
				if(a[mid] <= find)
					l = mid ;
				else
					r = mid - 1;
			}
			return l;
	}

例如 在 1 3 3 7 9 中找 3 ,将会返回 2 (下标),找 4 则会返回 2 (对应3),找 2 则会返回 0 (对应第一个1),如果find不在1-9这个范围,则返回离他近的下标。

返回从右往左第一个符合条件的下标 模板:
[l , r] 区间被划分成 [l , mid - 1] , [mid , r]
需要注意的是,mid = l + r +1 >> 1 , 这里有个加一,如果没有加一的话,假设 l = r - 1 , 则 mid = l , 如果测试条件通过的话,l = mid = l,进入死循环,上面的不会是因为如果测试条件通过, r = mid = l,此时 r = l ,会退出循环

	int binary_search(int a[],int n,int find)
	{
			int l = 0,r = n-1;
			while(l < r)
			{
				int mid = l + r +1 >> 1;
				if(测试条件)
					l = mid ;
				else
					r = mid - 1;
			}
			return l;
	}

浮点二分

浮点二分和整数二分思想一样每次把区间缩小一半,但是它每次取中间都是能取到一个特定的值的。所以最后 l 和 r 最后是不会相等的,但是我们可以确定一个区间长度 r - l > 这个区间长度。

举个例子,一个开方案例的二分

#include<iostream>
using namespace std;

int main()
{
	double x;
	cin>>x;
	
	double l = 0,r;
	if(x >= 1)	r = x;
	else 	r = 1;		//当x小于1时,答案不在{0,x}内
	while(r - l > 1e-8)  //可用for循环代替
	{
		double mid = (r + l)/2;
		if(mid * mid >= x)
			r = mid;
		else
			l = mid;
	}
	
	cout<<l<<endl; 
	
	return 0;
}

C++ STL 中的lower_bound , upper_bound

lower_bound 和 upper_bound 都是二分查找。

在升序数组中:
lower_bound( begin,end,num) 从数组的begin位置到end-1位置,二分查找第一个 >= num 的数,并返回地址,如果找不到一个 >= num 的数则返回end,返回的地址减去首地址(begin),即可得到下标。

upper_bound( begin,end,num) 与lower_bound 类似,但是不同的是它是找第一个 > num 的数,找不到同样返回 end 。

在降序数组中需要传递第四个参数 greater() :
lower_bound( begin,end,num,greater() ) 从数组的begin位置到end-1位置,二分查找第一个 <= num 的数,并返回地址,如果找不到一个 <= num 的数则返回end,返回的地址减去首地址(begin),即可得到下标。

upper_bound( begin,end,num,greater()) 与lower_bound 类似,但是不同的是它是找第一个 < num 的数,找不到同样返回 end 。

#include<bits/stdc++.h>
using namespace std;

int a[5] = { 1 , 3 , 3 , 7 , 9 };
int q[5] = { 9 , 7 , 3 , 3 , 1 };

int main()
{
	int low = lower_bound(a,a+5,3) - a;
	cout<<a[low]<<' '<<low<<endl;
	low = lower_bound(a,a+5,0) - a;
	cout<<a[low]<<' '<<low<<endl;
	
	int up  = upper_bound(a,a+5,3) - a;
	cout<<a[up]<<' '<<up<<endl;
	up  = upper_bound(a,a+5,0) - a;
	cout<<a[up]<<' '<<up<<endl;
	
	cout<<endl;
		
	low = lower_bound(q,q+5,3,greater<int>() ) - q;
	cout<<q[low]<<' '<<low<<endl;
	low = lower_bound(q,q+5,11,greater<int>() ) - q;
	cout<<q[low]<<' '<<low<<endl;
	
	up = lower_bound(q,q+5,3,greater<int>() )  - q;
	cout<<q[up]<<' '<<up<<endl;
	up = lower_bound(q,q+5,11,greater<int>() )  - q;
	cout<<q[up]<<' '<<up<<endl;
}


/*结果
3 1
1 0
7 3
1 0

3 2
9 0
3 2
9 0*/

猜你喜欢

转载自blog.csdn.net/yulong_D/article/details/105242879
今日推荐