Algorithm 二进制搜索中值逻辑

Algorithm 二进制搜索中值逻辑,algorithm,math,bit-manipulation,binary-search,integer-overflow,Algorithm,Math,Bit Manipulation,Binary Search,Integer Overflow,我已经用自己的努力递归地编写了二进制搜索第一个有效的原因是 它在数学上是相同的:l+(h-l)/2=l+h/2-l/2=l/2+h/2=(l+h)/2,以及 因为操作的优先级:首先是括号,然后是2除,然后是加法 不过,有趣的是,这个“解决方案”可能仍然会在一个较大的负值较低的值上溢出,因此它并不是您最初问题的真正解决方案 您可以按照low/2+high/2的思路进行操作,以避免溢出,但您需要显式写出偶数(如上)、偶数奇数、奇偶和奇数奇数的计算,以保留在int空间中。在执行此操作时,您可以利用

我已经用自己的努力递归地编写了二进制搜索第一个有效的原因是

  • 它在数学上是相同的:
    l+(h-l)/2=l+h/2-l/2=l/2+h/2=(l+h)/2
    ,以及
  • 因为操作的优先级:首先是括号,然后是2除,然后是加法
不过,有趣的是,这个“解决方案”可能仍然会在一个较大的负值
较低的值上溢出,因此它并不是您最初问题的真正解决方案

您可以按照
low/2+high/2
的思路进行操作,以避免溢出,但您需要显式写出偶数(如上)、偶数奇数、奇偶和奇数奇数的计算,以保留在
int
空间中。在执行此操作时,您可以利用
>>
来避免实际的除法。

(高+低)>>>1
中,仍然可以有符号换行,但是
>>
运算符将其左操作数视为无符号,因此有符号换行不相关。这种方法之所以有效,是因为不存在无符号环绕:
high
low
是非负的(作为有符号整数),因此作为无符号整数,它们不能大到足以导致无符号环绕

添加两个有符号非负整数不会受到无符号环绕的影响,这可以通过添加最大可能的数字来看出:2k-1-1+2k-1-1(其中k是整数类型的大小(以位为单位),通常为32),加起来就是2k-2。这还没有结束:最高的可表示数字是2k-1


因此,真正导致问题的不是
high+low
中的“溢出”,至少在有符号算术安全的合理语言中,如Java。将
high+low
的结果作为一个带符号的整数,然后用一个假设的
/2
处理,这会带来麻烦。

假设您的整数是16位带符号的(为了简洁起见;如果需要32位整数,请放大它们)

范围是-32768…32767

low+(high-low)/2
将溢出的示例:

low = -20000
high = 30000
high - low = 50000 = (after overflow) -15536
(high - low) / 2 = -7768
low - (high - low) / 2 = -27768
low = -20000
high = -10000
low + high = -30000 = (binary) 1000101011010000
(low + high) >>> 1 = (binary) 0100010101101000 = 17768
(高+低)>>1
将溢出的示例:

low = -20000
high = 30000
high - low = 50000 = (after overflow) -15536
(high - low) / 2 = -7768
low - (high - low) / 2 = -27768
low = -20000
high = -10000
low + high = -30000 = (binary) 1000101011010000
(low + high) >>> 1 = (binary) 0100010101101000 = 17768
在没有任何溢出可能性的情况下计算平均值是低效的,可以通过多种方式执行:

  • 首先转换为更高的“精度”,例如32位到64位;在计算平均值后转换回
  • 将数字除以2,然后使用某种形式的“余数”

    我不确定这个确切的代码是否有效;这只是一个想法

  • 用通常的方法计算平均值,然后检查“意外”结果(平均值小于
    low
    或大于
    high
    )。如果异常,则以“安全”方式计算

  • 以某种方式确保您的输入不会导致溢出。这不适用于库,但通常适用于实际应用程序,在实际应用程序中,所有数字的上限都是10000。或者也许你的数字是非负的;然后
    low+(high-low)/2实际上不能溢出


  • 是不是应该是(高+低)>>>1?@jackycflau抱歉,修正了,是的,在你回答之前我不知道wrapparound是溢出的同义词。谢谢你的回答。然而,为什么无符号整数不能大到足以导致无符号环绕?你能举个例子吗?@snr它们不是完全的同义词,例如在C中,带符号的加法可以溢出,但可能只有换行符,它也可能导致各种各样的破坏。可能是换行符?有符号整数变量在C语言中没有环绕行为@这只是意味着没有保证,并不是说它肯定不会发生是的,对了,为什么无符号整数不能大到足以引起无符号环绕?你能举例说明吗?谢谢。相同的代码确实是有帮助的。<代码>低/ 2 +高/ 2 < /代码>听起来不是一个好的解决方案:考虑“代码>低1=/代码>和<代码>高= 3 < /代码>:然后,代码>低/ 2 +高/ 2 < /代码>再次给出<代码> 1 < /代码>(假设整数除法)。现在更正了,请从另一个角度询问您。也许你的数字是非负的;那么low+(高-低)/2实际上不能溢出。是的,这是正确的,因为数组索引从0开始。