以下是我从TopCoder关于二进制搜索的教程中得到的伪代码
binary_search(A, target):
lo = 1, hi = size(A)
while lo <= hi:
mid = lo + (hi-lo)/2
if A[mid] == target:
return mid
else if A[mid] < target:
lo = mid+1
else:
hi = mid-1
// target was not found
Run Code Online (Sandbox Code Playgroud)
为什么我们计算中间值为mid = lo +(hi-lo)/ 2?(hi + lo)/ 2错了
我有一点想法,可能是为了防止溢出,但我不确定,也许有人可以向我解释,如果还有其他原因.
vto*_*tor 18
虽然这个问题已经有5年了,但googleblog上有一篇很棒的文章解释了这个问题和解决方案,这个问题值得分享.
需要提一下的是,目前在Java mid = lo + (hi - lo) / 2计算中的二进制搜索实现并未使用,相反,使用零填充右移运算符的更快更清晰的替代方案
int mid = (low + high) >>> 1;
Abh*_*nia 11
从后面的同一个教程:
"你也可能想知道为什么mid使用mid = lo +(hi-lo)/ 2而不是通常的mid =(lo + hi)/ 2来计算.这是为了避免另一个潜在的舍入错误:在第一种情况下,我们希望除法总是向下舍入,朝向下界.但是除法截断,所以当lo + hi为负时,它将开始向更高的边界四舍五入.以这种方式编码计算确保分割的数字总是正的因此我们总是按照我们的要求进行舍入.虽然当搜索空间只包含正整数或实数时,错误不会出现,但我决定在整篇文章中以这种方式对其进行编码以保持一致性."
小智 6
假设我们正在搜索的数组的长度为 INT_MAX。因此最初:
high = INT_MAX
low = 0
Run Code Online (Sandbox Code Playgroud)
在第一次迭代中,我们注意到目标元素大于中间元素,因此我们将起始索引移动到 mid ,如下所示
low = mid + 1
Run Code Online (Sandbox Code Playgroud)
在下一次迭代中,计算 mid 时,计算公式为 (high + low)/2,本质上转换为
INT_MAX + low(which is half of INT_MAX + 1) / 2
现在,该操作的第一部分(即(高 + 低))将导致溢出,因为我们将超过最大 Int 范围(即 INT_MAX)