了解二分搜索错误

Posted

技术标签:

【中文标题】了解二分搜索错误【英文标题】:Understanding Binary Search bug 【发布时间】:2016-04-05 05:28:44 【问题描述】:

我试图理解byte 数组的二分搜索 错误,我理解了在计算mid 索引时发生的溢出概念。但是,当我使用 byte 数组模拟相同的行为时,如下所示:

public byte binarySearch(byte[] arr, byte low, byte high, byte value)

        if(low>high)
            return -1;
        

        /* Line 1 */  byte overflow_mid = (byte) (((byte) (low + high))/2); // This line giving overflow behaviour

        /* Line 2 */  byte mid = (byte) ((low + high)/2);      // however this line doesn't, which is not what i expected

        if(arr[mid]== value)
            return mid;
        

        if(arr[mid]>value)
            return binarySearch(arr, low, (byte) (mid-1), value);
        
        return binarySearch(arr, mid, high, value);
    

我的直觉:

由于 low 和 high 变量的类型为 byte,我相信它不需要在第 2 行计算 mid index 时再次显式转换为 byte

谢谢

【问题讨论】:

为什么将byte 用于lowhigh?它们是索引值,而不是数组的值,所以只需使用 int 就不会出现任何溢出问题,而且它将消除对所有这些 dang casts 的需要。无论如何,数组索引值都会提升为int(请参阅JLS 15.13 Array Access Expressions),因此您并没有真正节省任何东西。 是的,你是绝对正确的,但我试图通过使用字节索引和字节数组模拟整数行为来理解这个错误,所以我希望它会崩溃。只是出于好奇。 【参考方案1】:

假设byte low = 50, high = 100

表达式low + high 将首先将两者提升为int,然后将它们相加,得到值150 (int)

在版本 1 中,您将 150 (int) 转换为 byte,即值 -106 (byte)溢出。与+ 相同,/ 运算符会将两边提升为int,因此它变为-106 (int),即-53 (int) 除以2。最后你再次转换为byte,以-53 (byte)结束。

在版本 2 中,您将 150 (int) 除以 2,并且由于双方都已经是 int 值,因此没有进行任何提升,最终得到 75 (int)。将其转换为byte 会得到75 (byte)没有溢出

【讨论】:

哦,这也是我的直觉。不知道运算符仅与 int 一起使用。该死的,你Java。大声笑谢谢@Andreas【参考方案2】:

您正在投射两个非常不同的值。

在您的第一行中,您进行了两次演员表。第一个溢出。您将low + high 的结果转换为字节,在您的情况下会溢出。

但是,在您的第二行中,您将(low + high) / 2 转换为byte,并假设lowhigh 都是正数,这意味着结果r 必须是low < r < high,因为@ 987654328@ 和high 可以用byte 变量表示,因此结果r 也可以表示,并且不会溢出。

【讨论】:

但不应该将两个字节变量相加成一个字节,然后在这种情况下会溢出。即如果低 = 63 且高 = 126(均以字节为单位)则低 + 高 = -67 否,因为 low + high 被评估为两个 整数 的总和,结果是 integer 本身,这就是为什么您需要转换为 byte 的原因第一名。 是的,明白了。谢谢@Ori Lentz

以上是关于了解二分搜索错误的主要内容,如果未能解决你的问题,请参考以下文章

详谈二叉搜索树

算法第二章上机实践报告

[JavaScript 刷题] 二分搜索 - 第一个错误的版本,Leetcode 278

LeetCode 题集:二分搜索

使用向量的二分搜索

二分搜索