二分查找的学习

1.为什么要学习二分查找:

  因为二分查找的思路虽然简单,但是在细节上往往容易出错,所以写一篇文章帮助自己复习巩固二分查找。

2.二分查找的目标:

3.思路:

1) 我们可以假设一开始整个数组都是灰色的。

2)设立两个指针,一个为 l = -1(从左往右),一个为 r = n(由右往左),从左边到 l 指针的范围为蓝色区域,从右边到 r 指针的范围为红色区域( l 初始值应该为左边界值 -1,r 初始值应为右边界值 +1)。

3)如图中左边的二分查找的伪代码,使用循环最终实现2)中图的结果。m为中间的指针(是分界线),我们以蓝色区域举例,如果m在满足蓝色区域条件(IsBlue),那么 l 更新为 m,否则m在红色区域,r 更新为 m。经过多次循环就能得到结果,一般来说,是需要再进行一次判断和题目要求才看是否return l or r(也有可能是-1)。

4)疑惑:为什么 l=-1,r=n?

这样可以避免出现都为蓝色或者红色区域的情况。

5)举例各查找要求中IsBlue的条件和return的指针情况。可以看看是否完全理解。

4.示例代码:

#include<bits/stdc++.h>
using namespace std;
vector<int> v(100005);
int n,q;
int BinarySerach1(int x){//二分查找的代码1
	int l=-1,r=n,m;
	while(l+1!=r){
		m=(l+r)/2;
		if(v[m]<x){//if是IsBlue的函数
			l=m;
		}else{
			r=m;
		}
	}
	if(v[r]==x){//注意这里的判断数组的下标是要和返回的r一致
		return r;
	}
	return -1;
}
int BinarySerach2(int x){//二分查找的代码2
	int l=-1,r=n,m;
	while(l+1!=r){
		m=l+r >> 1;//>> 1是右移,除2
		if(v[m]<=x){
			l=m;
		}else{
			r=m;
		}
	}
	if(v[l]==x){注意这里的判断数组的下标是要和返回的l一致
		return l;
	}
	return -1;
}
int main(){
	cin >> n >> q;

	for(int i=0;i<n;i++){
		cin >> v[i];
	}
	while(q--){
		int t;
		cin >> t;
		int index1=BinarySerach1(t);
		int index2=BinarySerach2(t);
		cout << index1 << ' ' << index2 << '\n';
	}
	return 0;
}

5.注意点:

 要在递增或者递减前提下,如果没有说明要先排序。

可能会出现没有红蓝区域的情况,这个时候需要对索引进行判断,查看是否在合理区间内[0,n)

6.复习视频链接:(如果还不懂的话)

1)二分查找为什么总是写错?(原视频)

2)讲解这个二分查找视频的步骤及其他 

7.拓展:C++ STL的二分查找(不要忘记先排序哦)

1)binary_search(a.begin(), a.end(), val)函数,返回的是一个bool类型,val是你想查找的值,如果找到了返回true,没有则false

2)lower_bound( )和upper_bound( ),一个有包含等于,可以通过upper(上界)来记忆有没有等于

        lower_bound( begin,end,num):二分查找第一个大于或等于num的数字,找到返回该数字的地址不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

        upper_bound( begin,end,num):二分查找第一个大于num的数字,找到返回该数字的地址不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

 可以通过*it(返回的地址)来得到值,可以同时使用upper和lower来确认这个值的个数。如

            int target = -(a[i] + b[j]);
            auto lower = lower_bound(c.begin(), c.end(), target); 
            auto upper = upper_bound(c.begin(), c.end(), target); 
            count += (upper - lower); 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值