码迷,mamicode.com
首页 > 其他好文 > 详细

二分查找总结

时间:2018-05-01 23:41:08      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:one   判断   简单   奇数   搜索   相等   while   最小   缩小   

二分搜索?莫非就是对于一个值单调递增的序列,给出\(l,r\),将要找的值与区间\([l,r]\)的中点值\(a[m]\)比较,大了\(l\)变成\(m\),小了\(r\)变成\(m\)呗?但是如果不细究,很容易发生off one错误。下面我们将要讨论该问题。

序列内没有重复数字

int Bsearch(int l, int r, int key, int *a)
{
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if (a[mid] == key)
            return mid;
        if (key < a[mid])
            l = mid + 1;
        else
            r = mid - 1;
    }
    return -1;
}

因为没有重复数字,所以如果mid的值就是所求,返回mid就可以,否则既然mid的值无效了,范围缩小后的区间就不包括mid了。

LowerBound和UpperBound

int LowerBound(int l, int r, int key, int *a)
{
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if (key <= a[mid])
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

int UpperBound(int l, int r, int key, int *a)
{
    while(l < r)
    {
        int mid = (l + r + 1) >> 1;
        if (key >= a[mid])
            l = mid;
        else
            r = mid - 1;
    }
    return l;
}

定义

LowerBound:给出\(l,r,x\),通过给出\(p\)的形式,求得一个区间\([p,r]\),使得任意一个下标\(k\),\(k\in [p,r]\Leftrightarrow a_k\geq x\)
UpperBound:给出\(l,r,x\),通过给出\(p\)的形式,求得一个区间\([l,p]\),使得任意一个下标\(k\),\(k\in [l,p]\Leftrightarrow a_k\leq x\)
\(m=\frac{l+r}{2}\)
左区间:\([l,\lfloor m\rfloor]\),右区间:\([\lceil m\rceil,r]\)
在LowerBound代码中,mid为\(\lfloor m\rfloor\);在UpperBound代码中,mid为\(\lceil m\rceil\)

原理

看看两个代码中mid的定义,发现无论是UpperBound,还是LowerBound,其缩小区间时,要么缩小到左区间,要么缩小到右区间。

序列中存在\(a_k=x\)

这意味着\(k\)的值可能有多个。

\(r-l+1\)为偶数

这意味着\(m\notin \mathbb{Z}\)。如果\(a_{\lfloor m\rfloor},a_{\lceil m\rceil}\)中存在不多于1个与\(x\)相等,这简单,若\(x\geq a_{\lceil m\rceil}\),则转移到右区间;若\(x\leq a_{\lfloor m\rfloor}\),则转移到左区间。两个代码都满足这个要求。
如果\(a_{\lfloor m\rfloor},a_{\lceil m\rceil}\)两个值都与\(x\)相等,则因为LowerBound要的\(k\)值最小,所以它要舍弃\(a_{\lceil m\rceil}\),在左区间中寻找\(k\leq\lfloor m\rfloor,a_k=x\),故要求转移到左区间。同理UpperBound要求转移到右区间。

\(r-l+1\)为奇数

这意味着\(m\in\mathbb{Z}\)。若\(a_m\neq x\),则若\(x<a_m\),则转移到左区间,否则转移到右区间;
\(a_m=x\),LowerBound要在左区间中寻找\(k\leq\lfloor m\rfloor,a_k=x\),故要求转移到左区间。同理UpperBound要求转移到右区间。

序列中不存在\(a_k=x\)

一开始是普通的二分,最后会遇到这种情况:\(m\notin\mathbb{Z}\)\(a_{\lfloor m\rfloor}<x<a_{\lceil m\rceil}\)。如果是LowerBound,因为\(x>a_{\lfloor m\rfloor}\),LowerBound的定义要求所得区间内所有值都要大于\(x\),故要舍弃\(a_{\lfloor m\rfloor}\),故转移到右区间;UpperBound同理转移到了左区间。

我们看到mid的定义以及小于大于等于判断及其操作,都满足上述要求。

二分查找总结

标签:one   判断   简单   奇数   搜索   相等   while   最小   缩小   

原文地址:https://www.cnblogs.com/headboy2002/p/8977085.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!