在本文中:http://googleresearch.blogspot.sg/2006/06/extra-extra-read-all-about-it-nearly.html,它提到最快的排序算法有一个错误(左+右)/ 2,它指出解决方案使用的是left+(right-left)/2
而不是{{1} }。
解决方案也在问题Bug in quicksort example (K&R C book)?
我的问题是为什么(left+right)/2
可以避免溢出?怎么证明呢?提前谢谢。
答案 0 :(得分:8)
根据定义,您有left < right
。
因此,right - left > 0
,以及left + (right - left) = right
(来自基本代数)。
因此left + (right - left) / 2 <= right
。因此,不会发生溢出,因为操作的每一步都受right
的值限制。
相比之下,请考虑错误的表达式(left + right) / 2
。 left + right >= right
,由于我们不知道left
和right
的值,因此该值完全有可能溢出。
答案 1 :(得分:3)
基本逻辑。
left <= MAX_INT
right <= MAX_INT
left+(right-left)
等于right
,每{2}已经<= MAX_INT
left+(right-left)/2
必须也是<= MAX_INT
,因为x/2
始终小于x
。与原始
比较left <= MAX_INT
right <= MAX_INT
left+right <= MAX_INT
(left+right)/2 <= MAX_INT
其中语句3显然是错误的,因为left
可以是MAX_INT
(语句1),right
也可以(语句2)。
答案 2 :(得分:3)
假设(为了使示例更容易),最大整数为100,left = 50
和right = 80
。如果你使用天真的公式:
int mid = (left + right)/2;
添加会导致130
溢出。
如果您改为:
int mid = left + (right - left)/2;
你不能在(right - left)
中溢出,因为你从较大的数字中减去一个较小的数字。这总是导致更小的数字,因此它不可能超过最大值。例如。 80 - 50 = 30
。
由于结果是left
和right
的平均值,因此它必须位于它们之间。由于它们都小于最大整数,它们之间的任何东西也都小于最大值,所以没有溢出。
答案 3 :(得分:0)
一个简单的工作示例将显示它。为简单起见,假设数字溢出999
以上。如果我们有:
left = 997
right = 999
然后:
left + right = 1995
在我们到达/2
之前已经溢出。但是:
right - left = 2
(right-left)/2 = 1
left + (right-left)/2 = 997 + 1 = 998
所以我们避免了溢出。
更普遍(正如其他人所说):如果left
和right
都在范围内(假设为right > left
),则(right-left)/2
将在范围内,因此必须left + (right-left)/2
,因为这必须小于right
(因为您将left
增加了right
之间差距的一半。
答案 4 :(得分:0)
(这是一个直观的解释而不是证明。)
假设您的数据为unsigned char
,left = 100
和right = 255
(因此right
为范围边缘)。
如果你执行left + right
,那么你将获得355,这不符合unsigned char
范围,因此会溢出。
但是,(right-left)/2
的数量为X
,left + X < right < MAX
为MAX
,其中unsigned char
为{{1}}为255。这样,您可以确保总和永远不会溢出。
答案 5 :(得分:0)
由于Java中的int数据类型为32位(假定是一种编程语言),因此超过32位的任何值都会被翻转。用数字表示,这意味着在Integer.MAX_VALUE(2147483647)上增加1后,返回值将为-2147483648。
来到上面的问题,我们假设以下内容:
int left = 1;
int right = Integer.MAX_VALUE;
int mid;
案例1:
mid = (left +right)/2;
//Here the value of left + right would be -2147483648 which would overflow.
案例2:
mid = left + (left - right)/2;
//This would not have the same problem as above as the value would never exceed "right".
理论上:
这两个值均与 left +(right-left)/ 2 =(2 * left + right-left)/ 2 =(left + right)/ 2
希望这可以回答您的问题。