深刻理解二分(折半查找)

一、引言:

二分查找算法真是一个老生常谈的话题了,相信很多人都能解释出二分查找算法的原理并加以一定的演示。但是如果让你空手码出一段没有bug的二分查找的代码,恐怕就没有说的那么简单了(十个二分九个错)。归根结底,还是自己对算法的细节部分没有完全掌握,即区间问题
大家一定见过不同版本的二分算法,有的while判断条件是<=,有的while判断条件是<;有的mid=r,有的mid=r-1。(这就是不同区间表示形式所导致的)

二、左闭右开区间:[l,r)

int binary_search1(int array[], int n, int key)
{
    int mid, l = 0, r = n; //此时数组区间表示为[0,n) 等价于 [0,n - 1]。
    while (l < r){              /*合法的区间是二分查找的前提,极限情况下左右边界最后汇聚于一点,
                                    所以在左闭右开的情况下,合法区间的左边界<右边界。不存在[a,a)这种区间*/
        mid = l + (r - l) / 2;
        if (array[mid] > key) { //查找的值小于arrary[mid],即在中点左侧。[l,r) = [l,mid - 1] + [mid,r)。
            r = mid;                    //区间更新为[l,mid) 等价于 [l,mid - 1]。
        }
        else if (array[mid] < key) {    //查找的值大于arrary[mid],即在中点右侧。[l,r) = [l,mid] + [mid + 1,r)。
            l = mid + 1;                        //区间更新为[mid + 1,r)
        }
        else {
            return mid;     //array[mid] == key,即找到key值,返回对应的数组下标
        }
    }
    return -1;                  //没有找到key值,返回-1
}

三、左闭右闭区间:[l,r]

int binary_search2(int array[], int n, int key)
{
    int mid, l = 0, r = n - 1;//此时数组区间表示为[0,n - 1] 等价于 [0,n)。
    while (l <= r) {                /*合法的区间是二分查找的前提,极限情况下左右边界最后汇聚于一点,
                                        所以在左闭右闭的情况下,合法区间的左边界<=右边界。存在[a,a]这种区间*/
        mid = l + (r - l) / 2;
        if (array[mid] > key) { //查找的值小于arrary[mid],即在中点左侧。[l,r] = [l,mid - 1] + [mid,r]。
            r = mid - 1;                //区间更新为[l,mid - 1] 等价于 [l,mid)。
        }
        else if (array[mid] < key) {    //查找的值大于arrary[mid],即在中点右侧。[l,r] = [l,mid] + [mid + 1,r]。
            l = mid + 1;                        //区间更新为[mid + 1,r]
        }
        else {
            return mid;     //array[mid] == key,即找到key值,返回对应的数组下标
        }   
    }
    return -1;                  //没有找到key值,返回-1
}

四、总结:

1.[a,b)
2.[a,b]
当我们选择了一种区间的表达形式后,就要在代码体现左右边界的地方进行相应的处理。不要混用区间的表达形式,比如起初你选择[a,b)这种区间表达形式,而接下来又不知不觉把区间表达形式写成了[a,b]。这种错误完全是可以避免的,不要把问题复杂化,简单的说就是一条路走到底。
相信很多二分查找的bug都源于区间开闭问题,只要理解了两种区间的相同之处和不同之处,无论是什么版本的二分你都可以一眼看出其中的对与错。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值