第一次盲写二分查找的打脸

所谓的盲写,就是在百度百科上简单看了一眼二分查找的原理,在纸上画画伪码,一拍脑袋:哦,想清楚了,小菜一碟。然后下笔如有神,语法都不带检查的大笔一挥,得到第一版代码。

public static int doSearch(int[] arry, int target){
        
        // because arry is ASC
        if (target < arry[0] || target > arry[arry.length-1]) {
            return -1;
        }
        
        int low_index = 0;
        int high_index = arry.length-1;
        int mid_index;
        
        while (low_index < high_index) {
            mid_index = low_index + (high_index - low_index)/2;
            int mid_val = arry[mid_index];
            if (target > mid_val) {
                low_index = mid_index;
                continue;
            }
            
            if (target < mid_val) {
                high_index = mid_index ;
                continue;
            }
            
            if (target == mid_val) {
                return mid_index;
            }
        }
        
        return -1;
  }

low_index = mid_index + 1

单元测试一测,一个测试方法一直出不来,代码运算量并不大,果断有死循环。这也给自己提了个醒,测试方法应加上timeout。Debug一下,发现死循环发生在测试下边界值处。原来第一处打脸的地方是在 low_index = mid_index 。

原因分析一下是,当对low_index和high_index之间的区域折半时,得到的一半值mid_index永远会偏向low_index,也就是:恰好有中间整数,得到的就是中间值;如果没有中间整数值,则滑向最接近的低位整数。如果low_index和high_index刚好相差1,mid_index的计算结果一直等于low_index,循环陷在将mid_index的计算结果为low_index然后再赋给low_index中出不来。

因此,low_index = mid_index修改为low_index = mid_index + 1,同时high_index = mid_index - 1。这本身也是折半的原理所在:折半对比,目标大于半数值,从高于折半处截取重新查找(low_index = mid_index + 1);目标小于半数值,从低于折半处截取重新查找(high_index = mid_index - 1);总之不相等则丢弃折半处


while (low_index < =high_index)

当使用while (low_index < high_index),对于数组长度为5或者6时,索引处1的值查找不出来。原因在于最后一次折半前,高低位重合,跳出循环,而来不及计算mid_index。


最后的写法,通过测试

public static int doSearch(int[] arry, int target){
        
        // because arry is ASC
        if (target < arry[0] || target > arry[arry.length-1]) {
            return -1;
        }
        
        int low_index = 0;
        int high_index = arry.length-1;
        int mid_index;
        
        while (low_index < =high_index) {
            mid_index = low_index + (high_index - low_index)/2;
            int mid_val = arry[mid_index];
            if (target > mid_val) {
                low_index = mid_index + 1;
                continue;
            }
            
            if (target < mid_val) {
                high_index = mid_index - 1;
                continue;
            }
            
            if (target == mid_val) {
                return mid_index;
            }
        }
        
        return -1;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值