在二进制搜索实现中,显然:
mid = (low + high)/2
会导致溢出。我已阅读了大量文档(如this),以下内容可以解决问题:
mid = (low + high) >>> 1
然而,我没有看到为什么这会起作用的原因。任何人都可以对此有所了解吗?
答案 0 :(得分:2)
>>>
是Java中的无符号右移运算符(ref)。由于mid
,low
和high
是有符号整数,low
和high
的添加可能会溢出为负值。 >>>
忽略了这个结果的潜在负面因素,并将其转移到右边,好像它是一个无符号数(在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。
这是有效的,因为low
和high
被假定在0到2 ^ 31-1的范围内(假设我们在这里谈论int
)。 low+high
的最大可能值不大于2^32-2
,因此可由unsigned int
表示(如果Java中存在此类内容)。这样的东西在Java中不存在,所以我们现在已经溢出了。但是,逻辑移位运算符>>>
将其操作数视为无符号,因此这会得到预期的结果。
答案 3 :(得分:0)
正如其他答案中提到的,>>>
不是C
运营商。
但是,如果你想避免C
中的溢出,你可以试试这个:
mid = (high - low)/2 + low;