📜  许多二进制搜索实现中的问题

📅  最后修改于: 2021-04-24 04:16:33             🧑  作者: Mango

考虑下面的Binary Search函数的C实现,这有什么问题吗?

// A iterative binary search function. It returns location of x in
// given array arr[l..r] if present, otherwise -1
int binarySearch(int arr[], int l, int r, int x)
{
    while (l <= r)
    {
        // find index of middle element
        int m = (l+r)/2;
  
        // Check if x is present at mid
        if (arr[m] == x) return m;
  
        // If x greater, ignore left half
        if (arr[m] < x) l = m + 1;
  
        // If x is smaller, ignore right half
        else r = m - 1;
    }
  
    // if we reach here, then element was not present
    return -1;
}

除了一个微妙的东西,即“ m =(l + r)/ 2”,上述内容看起来还不错。对于l和r较大的值,它将失败。特别是,如果low和high的总和大于最大正整数值(2 31 – 1),它将失败。该总和溢出为负值,并且该值在被二除时保持为负。在C语言中,这会导致数组索引超出范围,从而导致无法预测的结果。

解决此问题的方法是什么?
以下是一种方法:

int mid = low + ((high - low) / 2); 

可能更快,并且可以说是清楚的(仅在Java,请参阅此内容):

int mid = (low + high) >>> 1; 

在C和C++(其中没有>>>运算符)中,可以执行以下操作:

mid = ((unsigned int)low + (unsigned int)high)) >> 1 

合并排序中也会出现类似的问题。

以上内容摘自google reasearch博客。

请同时参考,它指出上述解决方案可能并不总是有效。

当数组长度为2 30或更大,并且搜索反复移动到数组的后一半时,会发生上述问题。这么大的数组不太可能在大多数时间出现。例如,当我们尝试使用32位代码块编译器的以下程序时,会出现编译器错误。

int main()
{
    int arr[1<<30];
    return 0;
}

输出:

error: size of array 'arr' is too large

即使我们尝试使用布尔数组,该程序也可以正常编译,但是在Windows 7.0和Code Blocks 32位编译器中运行时会崩溃

#include 
int main()
{
    bool arr[1<<30];
    return 0;
}

输出:没有编译器错误,但是在运行时崩溃。

资料来源:
http://googleresearch.blogspot.in/2006/06/extra-extra-read-all-about-it-nearly.html
http://locklessinc.com/articles/binary_search/