一篇文章,带你看懂整数二分查找

前言

  1. 二分查找的对象必须已经排好序,这篇文章默认用排好序的数组来掩饰。
  2. 本人能力有限,还望各位大佬多多包涵
  3. 每一个算法都会有对应的c++算法模板(是y总的模板),我只是将这个模板背后的原理解释清楚而已 。

在这里插入图片描述

整数二分查找

大致思想

将一个数组分为左右两个区间,判断被查找数位于左还是右区间,循环查找,直到区间的长度为一时停止。

注意:使用二分查找时一定可以返回一个下标,但是不一定有解。
如:在数组[1,2,3,5,6,7,8] 中查找元素4,虽然会返回数组下标,但是对应的元素一定不是4。所以,根据题目的要求,有时候要判断返回下标所对应的元素是否和被查找数一致。


模板

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)    //模板一
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}


// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)   //模板二
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;  //为什么+1,防止死循环
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

为了方便大家理解,这里先给出模板,再具体解释。
我们可以发现:实现这个排序算法的逻辑并不难,但很容易遇到边界问题,造成越界访问或者死循环等后果。


模板解释

1、如何确定被查找数位于左还是右区间

观察模板可以发现,我们使用if(check(mid))进行判断。在实际的使用过程中,并不一定要写一个函数来实现这个功能。我们只要能把数组分为两个部分就可以。

  • 如:假设mid是数组下标的中间位置;x是被查找的数 ;数组arr按升序(从小到大)排序
  • 要将数组分为两部分,可以这样实现
    (1)、if(arr[mid]>=x) ------------- 左区间为[l,mid] 右区间为[mid+1,r]
    如果结果为true,那么x在左区间,下一次查找时更新查找区间r=mid
    否则x在右区间 下一次查找更新查找区间l=mid+1

    (2)、if(arr[mid]<=x) ---------------左区间为[l,mid-1] 右区间为[mid,r]
    如果结果为true,那么x在右区间,下一次查找时l=mid
    否则x在左区间,下一次查找时r=mid-1

注意:一般情况下,会将判断条件的分界点设为被查找数。 (如上例的<=x)

在上面的例子中,两种情况下的左区间和右区间划分方式分别都不相同,在下一点将会解释原因。


2、区间的划分规律

直接说结论:区间被分为[l,mid][mid+1,r] 还是 [l,mid-1][mid,r] 取决于 if()对数组的判断结果。
(1)、前面元素判断为true,后面元素判断为false,左右区间就分为[l,mid-1][mid,r]。

  • 此时就套用模板二。
    在这里插入图片描述
    为什么这么分呢?这里先不解释mid具体取值,先随便假设任意一个数都可以是mid。
    如果要满足if(arr[mid]<=x)true, mid可能的取值如下
    在这里插入图片描述
    我们不妨极端一点,将mid的取值分别定为true,false的分界点。
    先来看if(arr[mid]<=x)true的情况。
    在这里插入图片描述

总结:当前面为true,后面为false时
判断结果为true,被查找数的位置只能位于[mid,r]里。

对应的,如果结果为false,被查找数的结果只能在[l,mid-1]里。


(2)、前面元素判断为false,后面元素判断为true,左右区间就分为[l,mid][mid+1,r]。

此时调用模板一

在这里插入图片描述

这个证明和上一个情况类似,我就不重复证明了。感兴趣的大伙可以自己证明。

总结:前面为false,后面为true时
判断结果为true,被查找数的位置只能位于[l,mid]

对应的,如果结果为false,被查找数的结果只能在[mid+1,r]里。


3、解释mid的取值

可能大伙会疑惑,为什么在模板二中,mid = l+r+1>>1呢?
其实,可以简单理解为为了防止死循环和越界
在这里插入图片描述
使用模板二时:如果mid = l + r>>2 (注意:向下取整)
在这里插入图片描述


本篇文章到这里就结束了,大伙学会了吗?

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值