我学习算法/大o和我只是对此感到好奇。
使用
mid = (low+high)/2;
为了获得二进制搜索算法的中点,通常不鼓励,因为可能存在溢出错误。为什么会导致溢出错误,以及
mid = low + (high-low)/2;
防止出现此错误?
感谢。
答案 0 :(得分:5)
在第一种情况下,你计算的值(低+高)可能太大而不适合int,如果低和高都足够大(如果两者都等于2 ^ 30 + 1 /或甚至大于/)。在第二种情况下,你不计算(低+高),你做一个小技巧,你通过表达式(高 - 低),该表达式相对于int溢出更安全。
但是,如果你没有一个大小超过2 ^ 30的数组(无论如何都是一个非常庞大的数组),我看不出即使使用第一个表达式也会遇到int溢出。所以我会在大多数情况下使用第一个而不用担心。
答案 1 :(得分:1)
让我们假设整数最糟糕的情况。 如果我们看一下大局,我们确信mid =(low + high)/ 2永远不会溢出。假设low = 231-1和high = 231-1(最高整数值),总计算将是[2 *(231-1)] / 2 = 231-1。(int可以容纳的最大数字)
然而,我们计算它的方式很重要。
如果使用(低+高)/ 2进行计算,它只会在我们的情况下溢出,因为首先它会尝试总和低(231 -1)和高(231 -1)和BAM。 2 *(231-1)是溢出。它不能将它除以2,因为它最初不能将该值存储在int中。
如果使用低+(高 - 低)/ 2计算,则无法溢出。 这样想,低+(高 - 低)/ 2 =(低+ x),其中x =(高 - 低)/ 2。为了创建溢出,我们应该为双方选择大(在我们的情况下最大的int)数字。然而,如果我们选择最低点,那么x将是最小的(因为我们从x中的高点减去低点),反之亦然。
答案 2 :(得分:0)
每个基本数据类型都有最大值和最小值。当您超过该数据类型的最大值或最小值时,它将分别包装到最小值或最大值。
mid = (low+high)/2;
在这种情况下如果low+high>MAX_VALUE
那么你会得到奇怪的结果。
这是一个有趣的测试你可以尝试
int high = Integer.MAX_VALUE;
int low = 3*Integer.MAX_VALUE/4;
int mid = (high+low)/2;
System.out.println(mid); // -805306369
通过更改数学,您可以删除通过减去它们而不是添加它们来执行最大值或最小值的机会。