二分查找 【模板+中间值问题】

全文目录

  • 前言
  • 二分查找动图演示
  • 代码模板
  • ❗️ 使用哪个模板问题 ❗️
  • mid为何+1问题

前言

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。它要求元素具有有序性,或者具有跟有序性类似的性质,能够不断地缩小查找范围。

查找操作主要有一下几点:

1、确定需要查找的值,设立基准值(一般是中间值),设立判断条件,判断基准值是否满足某种性质

2、以基准值为边界,划分左右两个区间

3、根据判断条件是否成立,分析结果可能存在的区间,更新查找范围

4、重复以上操作,直到区间不存在(左边界大于右边界)或查找到需要的值时,查找结束


二分查找动图演示

二分查找 【模板+中间值问题】_第1张图片


代码模板

我们这里以整数的有序序列为例,演示二分查找的代码和需要注意的事项。整数二分的代码分为两种情况:

  1. 判断条件成立时新区间需要更新在左半区间,即[l, mid]
  1. 判断条件成立时新区间需要更新在右半区间,即[mid, r]

需要注意的是不管哪种情况,条件成立都需要将取到mid,因为mid可能为答案

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

// 查找左区间
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:条件成立,新区间在[l, mid]
int SearchLeft(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]时使用:条件成立,新区间在[mid, r]
int SearchRight(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

❗️ 使用哪个模板问题 ❗️

决定使用哪个模板,是根据check(mid)来决定的:

check(mid)就是判断答案在左半区间还是右半区间

1、如果check(mid)是判断答案在左半区间,使用SearchLeft模板(mid不需要+1):

如果在条件成立,说明答案在左半区间,也就是[l, mid],新区间为[l, mid],区间更新方式为r = mid
如果条件不成立,说明答案在右半区间,也就是[mid + 1, r],新区间为[mid + 1, r],区间更新方式为l = mid + 1

2、如果check(mid)是判断答案在右半区间,使用第二个模板(mid需要+1):

如果在条件成立,说明答案在右半区间,也就是[mid, r],新区间为[mid, r],更新条件为l = mid
如果条件不成立,说明答案在左半区间,也就是[l, mid - 1],新区间为[l, mid - 1],更新条件为r = mid - 1


mid为何+1问题

在这两种情况中,区间划分好理解,不就是一左一右、一加一减嘛。但是在mid为何需要加1可能会让很多人疑惑,我在学习的时候也是迷糊了好久。现在将从大佬那里总结到的经验分享一下:

1、在SearchLeftmid 为何不需要 +1

设左右两个边界只相差1,即l = r - 1时,如果 mid + 1mid 向下取整 ,即mid == r ,如果条件刚好成立的话,就会导致更新完区间后r还是等于mid,等于没有更新,这时候就是一个死循环了。所以mid 不需要 +1,进行向上取整,让mid == l,破坏死循环的条件。

2、在SearchRightmid为何需要 +1

设左右两个边界只相差1,即l = r - 1时,当mid不 +1 时mid是向上取整的,所以mid == l,如果条件刚好成立的话,就会导致更新完 区间后l还是等于mid,等于没有更新,这时候就是一个死循环了。所以需要mid+1进行向下取整,让mid == r,破坏死循环的条件。

大佬原话:

对于mid + 1与否我觉得是为了让区间平分
mid = left + right >> 1; 这里mid是上中位数
mid = left + right + 1 >> 1; 这里mid是下中位数
如果取left = mid, 即[mid, right], 则mid取下中位数才能平分区间
如果取right = mid, 即[left, mid], 则mid取上中位数才能平分区间


完结散花
二分查找 【模板+中间值问题】_第2张图片

你可能感兴趣的:(算法,数据结构,算法,c++)