二分查找爬过的坑

二分查找看似简单,但是刷多了二分查找的题,就会遇到很多意向不到的坑,真的是实践出真知啊,现总结下二分查找遇到的坑。

一 朴素版二分查找:在有序数组中查找关键字,找到就返回下标,不管重复不重复。

//朴素版二分查找
int bitsearch(int A[],int n,int k){
    int l=0,r=n-1;
    int mid;

    while(l <= r){ //为什么不是 l < r
        mid = l+((r-l)>>1); // 为什么不写成 (l+r)/2
        if(A[mid] == k){
            return mid;
        }else if(A[mid] > k){
            r = mid - 1;
        }else{
            l = mid + 1;
        }
    }

    return -1;
}

仔细看上边代码后面带注释的两部分,现在来解释下。
①循环条件为什么不是 (l<r)
第一,如果数组长度为1的话,不管查找什么都会恒定的返回-1,这显然是错的。
第二,当l + 1 = r的时候,mid=l,如果此时A[mid]小于target执行l=mid+1=r,再次循环时候while条件不满足,将退出循环,但是A[right]可能==target。考虑[3,5] k=5的情况,这时候会返回-1,但是5是存在的。
②为什么不写(l+r)/2
主要是考虑溢出的问题,如果l和r都很大,则l+r很可能越界,这时候是有问题的。mid = l+((r-l)>>1)不会出现溢出问题,而且移位操作比较节省时间。

二 找最小最大
有序非递减序列中,找k第一次出现的位置,可能有重复。

int findForstIndex(int A[],int n,int k){
    int l = 0,r = n - 1;
    int mid;

    while(l < r){
        mid = l+((r-l)>>1);
        if(A[mid] < k){
            l = mid + 1;
        }else{ // >=
            r = mid;
        }

    }
    if(A[r] == k) return r;
    return -1;
}

①如果用while(l<=r),则可能会出现死循环,如当l==r,A[mid]=A[l] >= k时,r=mid,再到while循环里判断仍然满足条件,因为是把r自己赋值非自己所以是死循环。
②while循环外部为什么还需要判断一次?
小于key的左半部分一定是被砍掉的,但while循环中被砍掉最后一个元素跳出循环后,剩下的一个元素可能有两种情况,key 和比key大的值,所以必须进行一次判断。

二 找最小最大
有序非递减序列中,找k最后一次出现的位置,可能有重复。

int findLastIndex(int A[],int n,int k){
    int l = 0,r = n - 1;
    int mid;

    while(l < r - 1){

        mid = l+((r-l)>>1);
        if(A[mid] > k){
            r = mid - 1;
        }else{ // <=
            l = mid;
        }


    }
    if(A[r] == k) return r;
    else if(A[l] == k) return l;
    return l;
}

①如果用while(l<r),则可能会出现死循环,如当l+1=r,A[mid]=A[l] <= k时,l=mid,再到while循环里判断仍然满足条件,因为是把l自己赋值非自己所以是死循环。
②while循环外部判断?
循环终止条件l==r-1,有可能l是也有可能r是,考虑全重复条件。所以先从最大的r开始判断。

总结:容易出错的点
1 循环终止条件
2 返回值
3 left,right的赋值
4 最好写几个数判断一下,尤其是特殊情况,如长度为1,l==r,l==r-1,key在两端的情况验证一下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值