谈一谈二分搜索的两种实现

1.前言

二分搜索是一种数据查找方法,可以在O(logn)时间复杂度内定位一个元素的在有序序列中的位置。是查找有序序列元素的必备方法,同时也可以用来搜索区间边界,进而将有序区间一分为二。本文就简单的介绍一下二分查找的实现方法和应用场景。

2.二分查找的两种写法

二分查找的思想很简单,就是每迭代一次,将目标元素所在的区间范围缩小为原来的一半。
二分查找存在两种写法,根据区间的划分不同,分为闭区间左闭右开区间两种,前者便于理解,但是后者具备了更多实用的特性。

方法一

这种方法的特征如下

  • 初始条件:
    • l=0,
    • r=array.length-1
  • 循环不变式:目标元素在区间[l, r]
  • 循环结束条件:l>r
  • 循环结束:此时目标元素所在区间为空,即目标元素target不在序列中
public int biSearch(int[] array,int target){
    int l=0;
    int r=array.length-1;
    while(l<=r){
        int m = l+(r-l)/2;
        //判断中位元素和target的关系,缩小[l,r]区间
        if(target == array[m]){
            return m;
        }
        else if(target < array[m]){
            r = m - 1;
        }
        else{
            l = m + 1;
        }
    }
    return -1;
}

循环会正确结束的证明:

  • m是[l,r]中的元素
  • 每一轮迭代[l,r]的距离一定会缩小1
  • 所以最后循环条件l<=r一定会打破

方法二

这种方法的特征如下

  • 初始条件:
    • 将序列划分为三个区间[0,l)[l,r)[r,array.length)
    • l=0
    • r=array.length
  • 循环不变式:
    • 区间[0,l)内的元素<target,
    • 区间[r,array.length)内的元素>=target
  • 循环结束条件:l==r
  • 循环结束:
    • 由于l==r区间[l,r)消失,只剩下区间[0,l)[r,array.length)
    • 根据循环不变式:l[l,array.length)区间的第一个元素,也即序列中>=target的第一个元素的索引
    • 如果array[l]!=target,array[l]就是>target的最小元素
    • ltarget在序列中的插入位置
public int biSearch(int[] array,int target){
    int l=0;
    int r=array.length;
    while(l<r){
        int m = l+(r-l)/2;
        else if(array[m]>=target){
            r = m;
        }
        else{
            l = m + 1;
        }
    }
    return l;
}

循环会正确结束的证明:

  • m[l,r]中的元素
  • 每一轮迭代[l,r]的距离一定会缩小1:
    • 只有当r==m时,不会缩小
    • 因为 r==mm = l + (r-l)/2
    • 所以 r = l + (r-l)/2
    • 所以 r -l = (r-l)/2
    • 所以 r -l == 0
    • 只有当 r - l==0时,可能存在死循环,这和循环条件l<r矛盾
  • 所以最后循环条件l<r一定会打破

3.总结

  • 方法1只适用于查找单个元素是否在序列中
  • 方法2可以看作一种寻找区间边界的方法,具有普适性:
    • 定义两个区间[0,l)[r,array.length)然后不断缩小这两个区间的边界[l,r)
    • 直到l==r,就找到了这两个区间的真正边界

4.参考

《编程珠玑》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值