二分搜索中值计算

时间:2010-12-26 15:29:17

标签: binary-search

以下是我从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

为什么我们将中间值计算为 mid = lo +(hi-lo)/ 2 (hi + lo)/ 2

错误

我有点想法可能是为了防止溢出,但我不确定,也许有人可以向我解释,如果还有其他原因。

5 个答案:

答案 0 :(得分:19)

是的,(hi + lo)/ 2可能会溢出。这是Java二进制搜索实现中的一个实际错误。

不,没有其他原因。

答案 1 :(得分:14)

虽然这个问题已有5年历史,但有一个great article in googleblog可以解释问题和详细解决方案,值得分享。

需要提及的是,在Java mid = lo + (hi - lo) / 2计算中的二进制搜索的当前实现中未使用,而是使用零填充右移运算符的更快且更清晰的替代方案< / p>

  

int mid = (low + high) >>> 1;

答案 2 :(得分:11)

后来在同一个教程中:

“你也可能想知道为什么mid使用mid = lo +(hi-lo)/ 2而不是通常的mid =(lo + hi)/ 2来计算。这是为了避免另一个潜在的舍入错误:第一种情况,我们希望除法总是向下舍入,朝向下界。但是除法截断,所以当lo + hi为负时,它将开始向更高的边界四舍五入。以这种方式编码计算确保数字划分总是积极的,因此总是按照我们的意愿进行舍入。虽然当搜索空间只包含正整数或实数时,错误不会出现,但我决定在整篇文章中以这种方式对其进行编码以保持一致性。“< / p>

答案 3 :(得分:6)

(hi+lo)确实可能溢出整数。在改进版本中,似乎从hi中减去lo然后再添加它是没有意义的,但有一个原因:执行此操作不会溢出整数它将导致一个数字与与hi+lo相同的parity,以便(hi+lo)/2的其余部分与(hi-lo)/2相同。然后可以在分割后安全地添加lo以达到相同的结果。

答案 4 :(得分:2)

让我们假设我们正在搜索的数组长度为 INT_MAX。 因此最初:

high = INT_MAX 
low = 0

在第一次迭代中,我们注意到目标元素大于中间元素,因此我们将起始索引移到中间作为

low = mid + 1

在下一次迭代中,计算mid时,计算为(high + low)/2 这基本上意味着 INT_MAX + low(which is half of INT_MAX + 1) / 2

现在,这个操作的第一部分,即(高 + 低)会导致溢出,因为我们要超过最大 Int 范围,即 INT_MAX