二进制搜索中的逻辑右移防止算术溢出

时间:2012-04-06 17:14:14

标签: c algorithm search

在二进制搜索实现中,显然:

mid = (low + high)/2

会导致溢出。我已阅读了大量文档(如this),以下内容可以解决问题:

mid = (low + high) >>> 1 

然而,我没有看到为什么这会起作用的原因。任何人都可以对此有所了解吗?

4 个答案:

答案 0 :(得分:2)

>>>是Java中的无符号右移运算符(ref)。由于midlowhigh是有符号整数,lowhigh的添加可能会溢出为负值。 >>>忽略了这个结果的潜在负面因素,并将其转移到右边,好像它是一个无符号数(在Java中,没有无符号数)。

在C和C ++中,这相当于

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

(在您链接的文章中明确提到)。

这最终与

相同
mid = ((unsigned int)low + (unsigned int)high)) / 2;

请注意,您可能不希望这样做。如果你要使用无符号值,你应该坚持使用无符号值,避免在有符号和无符号之间来回反复。

答案 1 :(得分:2)

相同的链接说明了使用Java的>>>的原因。理由是(低+高)可能超过'mid'可以容纳的最大值:

  

编程中的珍珠Bentley说类似的行“将m设置为   l和u的平均值,截断到最接近的整数。“在   面对它,这个断言可能看似正确,但它失败了   int变量的大值低和高。具体来说,它失败了   如果low和high之和大于最大正int   值(231 - 1)。总和溢出为负值和值   除以2时保持负值。在C中,这会导致数组索引   超出界限,结果不可预测。

它还说明了C中的等效操作:

  

...

     

在C和C ++中(你没有>>>运算符),你可以这样做:

     

6:mid =((unsigned int)low +(unsigned int)high))>> 1;

因此解决方案是完全阅读并理解该文章。

答案 2 :(得分:1)

C中没有“逻辑右移”(没有>>>运算符),所以你可能在谈论Java。

这是有效的,因为lowhigh被假定在0到2 ^ 31-1的范围内(假设我们在这里谈论int)。 low+high的最大可能值不大于2^32-2,因此可由unsigned int表示(如果Java中存在此类内容)。这样的东西在Java中不存在,所以我们现在已经溢出了。但是,逻辑移位运算符>>>将其操作数视为无符号,因此这会得到预期的结果。

答案 3 :(得分:0)

正如其他答案中提到的,>>>不是C运营商。

但是,如果你想避免C中的溢出,你可以试试这个:

mid = (high - low)/2 + low;