各种缺陷的二分法算法

本文深入探讨了二分法算法的实现细节及常见问题。通过分析不同版本的二分法代码,指出了容易忽视的边界条件处理问题,并提供了一种避免整数溢出的解决方案。

二分法是思想精髓就是如果左下标和右下标得到的中间下标所在的值等于所要查找的值,算法结束;如果中间的值小于目标值,则说明目标值可能在中间值和右下标所在的区间内,就将中间下标当成左下标,继续搜索。如果中间值大于目标值,则把中间下标当成右下标,继续搜索。

这是近期在网上用google搜索“二分法算法”找到的二分法算法。结果发现各种各样的缺陷。

public int erfen()
//二分法查找
{
int iindex=0; //相当于指针的东西
int istart=0; //
int iend=iarray.length-1;
while(true)
{
icount++;
iindex = (istart+iend)/2;
if(iarray[iindex]<iseek)
{
istart = iindex;
}
else if(iarray[iindex]>iseek)
{
iend = iindex;
}
else
{
break;
}
}
return icount;
}
用一个测试用例就能证明的这个算法错误。

0 1 2 3 4 5查找5.结果你会发现死循环。

很多人认为只要起始值的左值和右值相加为n-1就可以了。其实不然,二分法是10年多的时间才找到了一种正确的算法。如果你开始的左值设为0并且右值设为n-1,程序很大的程度上会错。除非你解决了最后的死循环问题。

下面的算法

left = - 1 ;

right
= length;

while (left <= right)

... {
mid
= (left + right) / 2 ;
if (a[mid] > value)

... {
// 中间值比目标值大
right = mid;
}

else if (a[mid] < value)
... {
// 中间值比目标值小
left = mid;
}

else
... {
// 找到,中间值等于目标值
return left;
}


}

return - 1 ;

可以解决上面的0 1 2 3 4 5 查找5找不到的问题。但是,却在查找不存在的数上出了问题。比如6

下面的代码解决了这个问题:

left = - 1 ;

right
= length;

while (left + 1 != right) // 注意这句话!!!

...
... {
mid
= (left + right) / 2 ;
if (a[mid] > value)

...
... {
// 中间值比目标值大
right = mid;
}

else if (a[mid] < value)
...
... {
// 中间值比目标值小
left = mid;
}

else
...
... {
// 找到,中间值等于目标值
return left;
}


}

return - 1 ;

但是上的这段真的解决了所有的问题?如果left + right 超过了整数范围?

改为下面的代码:

int BinarySearch( int value)
... {


int left = -1 ;
int right = length ;
int mid;
while (left+1! = right)
... {
mid
= left + (right - left) / 2 ; // 注意这里的写法
if (values[mid] == value)
... {
return mid;
}

else if (values[mid] < value)
... {
left
= mid;
}

else
... {
right
= mid;
}

}

return - 1 ;

}

这里解决了越界问题。但是这段代码真的没有问题了吗?没有人能保证。除非能用数学证明。

另外还有一种写法:但是必须特判length==0的情况,否则一定会访问越界。

int bsearch(int* a, int l, int r,int k) { int mid = 0; if(l-r == 0) return -1; while(l<=r){ mid = (l+r)/2; if(a[mid]<k) l = mid+1; else if(a[mid]>k) r=mid-1; else return mid; } return -1; }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值