1.1二分查找(容易忽视的关键点)

这是个自以为完全理解能上天,却敲码30秒debug半小时的悲惨故事(我果然是蒟蒻)

首先贴出自我感觉良好,但有bug的代码:

 

 1 osition BinarySearch( List L, ElementType X ){
 2     int left,right,mid;
 3     left=1;
 4     right=L->Last;
 5     mid=(left+right)/2;
 6     while(left!=right){
 7         if(X==L->Data[mid]){
 8             return mid;
 9         }
10         else if(X < L->Data[mid]){
11             right=mid;
12             mid=(left+right)/2;
13         }
14         else if(X > L->Data[mid]){
15             left=mid;
16             mid=(left+right)/2;
17         }
18         if(L->Data[mid]==X)return mid;
19         else if(X==L->Data[right])return right;
20     }
21     return NotFound;
22 }

 

此代码有两个问题表象问题:

1、为了找到尾部的情况,强行在循环末尾加了一个判断语句(这种治标不治本的写法,你好意思说自己是学算法的吗......)

2、当x找不到时,返回不了NotFound

其实这两个问题可以归结为同一个问题:没有理解中点的偏向问题!

 

由于 Java 语言(C、C++、Python 等也一样)的除法是自动向下取整,因此中间位置 mid 会偏向左边界 left,所以 left = mid +1而不是 left = mid。因为只要 left 和 right 不相等,left = mid+1 一定会较原来的 left 右移,这样可以确保范围不断缩小。

 

下面是最后一次循环的典型情况,目标值为 3,right 指针略过了大于或等于 3 的位置,直到第一个 3 处,此时 mid 由于向下取整,等于 left,经过判断,发现 mid 处的值为 2,比目标值小,因此 left = mid + 1,移动到了右侧的位置上。

 

 此时终止条件达成。

 

所以正确代码如下:

 1 Position BinarySearch( List L, ElementType X ){
 2     int left,right,mid;
 3     left=1;
 4     right=L->Last;
 5     mid=(left+right)/2;
 6     while(left!=right){
 7         if(X==L->Data[mid]){
 8             return mid;
 9         }
10         else if(X < L->Data[mid]){
11             right=mid;
12             mid=(left+right)/2;
13         }
14         else if(X > L->Data[mid]){
15             left=mid+1;
16             mid=(left+right)/2;
17         }
18         if(L->Data[mid]==X)return mid;
19     }
20     return NotFound;

 

 小结:遇到整数除法时,注意商的偏向问题。

 

 

 参考资料:

http://www.codebelief.com/article/2018/04/completely-understand-binary-search-and-its-boundary-cases/

 

转载于:https://www.cnblogs.com/yifeianyi/articles/11570157.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值