搜索
您的当前位置:首页解决二分查找中的无限循环问题

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

来源:乌哈旅游

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

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

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

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;
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Top