解决二分查找中的无限循环问题

前几次写二分查找时经常会遇到无限循环的问题,例如下面这道题。

输出一个数组中所求元素的起始位置与终止位置,例如a[6] = {0,1,2,3,4,4},查找4的起始位置与终止位置输出为:4 5

这个问题分为两部分:寻找>=目标的第一个数,以及<=目标的最后一个数(这里数的顺序是从左往右)。

寻找>=目标的第一个数很简单,代码如下

while (l < r)
{
	int mid = (l + r) >> 1;
	if (a[mid] >= tgt) r = mid;   /*tgt即为要查找的元素*/
	else l = mid + 1;
}

而寻找<=目标的最后一个数却经常写错,写成下面的这种形式:

while(l < r)
{
	int mid = (l + r) >> 1;
	if (a[mid] <= tgt) l = mid;
	else r = mid - 1;
}

为什么上面不会无限循环而下面会呢?
关键在于mid与l的变化。

我们先看错误的代码。

由于mid = (l + r) >> 1,即为(l + r) / 2,这个算式是向下取整的,假设l = 4,r = 5,那么mid的取值会是4,与l相等。假设在上一轮循环中,l = 3,r = 5,mid = 4,并且此时满足if语句,通过l = mid将l的值转变为4,那么在下一轮循环中mid的值依旧为4,且一定会继续满足if语句执行l = mid,l变量没有丝毫变化。 也就是会无限循环l与r相邻的情况,由于向下取整的特性,l会不断赋值为与其相等的mid。

我们再看上面不会出错的代码。
在这个代码里,l的赋值代码为l = mid + 1,并不会出现上面的错误。而因为mid是向下取整的,当l与r相邻时mid = l,所以r = mid并不会使其死循环。

解决方法

上面解释了由于mid向下取整的原因会导致l = mid不断循环,所以这里提供一个最简单的解决方法,那就是将mid向上取整,令mid = (l + r + 1) >> 1 即可实现,代码如下:

while(l < r)
{
	int mid = (l + r + 1) >> 1;
	if (a[mid] <= tgt) l = mid;
	else r = mid - 1;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值