【C/Java】详解二分查找算法-灵活划分红蓝区域法(写代码不再死循环)

目录

二分查找思路(划分红蓝区域法)

第一问.寻找第一次出现3的位置,应该如何进行划分区间然后找到正确的位置?

第二问.寻找最后一次出现3的位置,应该如何进行划分区间然后找到正确的位置?


这里用两个问题引入,详细理解二分查找

二分查找思路(划分红蓝区域法)

二分查找中,可以把l和r的指针看做是在划分两个红蓝区域,然后寻找边界目标值

设有q[N]数组,在算法开始时,l的指针是指向-1的,而不是0,且r初始化为n,而不是n-1因为在最初,我们是不知道数组里面元素的任何值的,不知道哪些是蓝色区域,哪些是红色区域。(并不是说不可以l=0,r=n-1,只是这样容易写错,并且需要考虑mid是否需要+1来使得算法满足需求,比较麻烦,且容易出现边界问题死循环)。

 伪代码如下

//假设查找数组范围为[0,N-1],需要查找x元素
//伪代码如下
check(x){
 return IsBlue(x);//判断是否满足蓝色区域条件
}

l=-1,r=n;
while(l+1!=r){
mid=(l+r)/2
if(check(x))l=mid;//假设l一直是包括蓝色部分区域,r是红色部分区域
else r=mid;
}
return l or r;


这样划分可以很容易来注意二分查找所带来的的边界问题,可看如下例子。

如我们需要在下面的序列中找出第一次出现3的位置和最后一次出现3的位置,且找出第一次出现3位置之前的第一个元素2的位置,最后一次出现3的位置的下一个元素4的位置下标。(也就是2 3 .. 3 4这四个元素的位置)如何进行寻找?

1 2 3 3 3 4

第一问.寻找第一次出现3的位置,应该如何进行划分区间然后找到正确的位置?

如上图,这样进行划分红蓝区域,在输出r,就是第一次出现3的位置了!同时返回l也找到了第一次出现3位置的左边第一个元素的位置也找到了。

第一问的C++和Java代码实现:

C

#include <iostream>
using namespace std;
const int N=6;
int q[N],x;

int binarySearchLower(int q[],int x){
	int l=-1,r=sizeof(q)/sizeof(q[0]);
	int mid;
	while(l+1!=r){
		mid=l+r>>1;
		if(q[mid]<x)l=mid;
		else r=mid;
	}
	return q[r]==x?r:-1;
}

int main(){
	int q[]={1,2,3,3,3,4};
	printf("%d",binarySearchLower(q,3));
	return 0;
}

Java


public class BinarySearch {
    /*
     *
     * q[]:查找的数组
     * x:查找的值
     * */
    public static int binarySearchLower(int q[],int x){
        int l=-1,r=q.length;
        while(l+1!=r){
            int mid =l+r>>1;//右移一位,相当于除于2:,如1111=>8+4+2+1。
            if(q[mid]<x)l=mid;//划分蓝色区域,
            else r=mid;//划分到了红色区域
        }
        return q[r]==x?r:-1;
        //如果这里输出l,就是2的位置
    }
    public static void main(String[] args) {
        int q[]=new int[]{1,2,3,3,3,4};
        System.out.println(binarySearchLower(q,3));

    }
}

第二问.寻找最后一次出现3的位置,应该如何进行划分区间然后找到正确的位置?

如上图所示进行划分,然后再返回l就可以找到最后一次出现3的位置了,如果输出r,就找到了最后一次出现3的位置的下一个元素。

第二问的C++和Java代码实现

c++

#include <iostream>
using namespace std;
const int N=6;
int q[N],x;

int binarySearchUpper(int q[],int x){
	int l=-1,r=N;
	int mid;
	while(l+1!=r){
		mid=(l+r)/2;
		if(q[mid]>x)r=mid;
		else l=mid;
	}
	return q[l]==x?l:-1;
}
int main(){
	int q[]={1,2,3,3,3,4};
	printf("%d",binarySearchUpper(q,3));
	return 0;
}

Java


public class BinarySearch {
    /*
     *
     * q[]:查找的数组
     * x:查找的值
     * */
    public static int binarySearchUpper(int q[],int x){
        int l=-1,r=q.length;
        while(l+1!=r){
            int mid =l+r>>1;//右移一位,相当于除于2:,如1111=>8+4+2+1。
            if(q[mid]>x)r=mid;//划分红色区域,
            else l=mid;//划分到了蓝色区域
        }
        return q[l]==x?l:-1;
    }
    public static void main(String[] args) {
        int q[]=new int[]{1,2,3,3,3,4};
        System.out.println(binarySearchUpper(q,3));

    }
}

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力奋斗的张同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值