binary search

这里主要讨论的是binary search的边界情况及处理。

参考 : http://my.oschina.net/fullofbull/blog/199693?fromerr=2T6aDmtE

经典版本:(注意,边界条件迭代、循环终止条件设定,中位数计算)

int binary_search(int *A, int n, int target)
{
    int low = 0, high = n - 1;
    assert(A != NULL && n >= 0);
    while (low <= high)
    {
        int mid = low + (high - low) / 2;
        if(A[mid] == target)
            return mid;
        else if (A[mid] < target)
            low = mid + 1;
        else
            high = mid - 1;
    }
    return -1;
}

这里查找的条件是:

        if(A[mid] == target)
            return mid;
        else if (A[mid] < target)
            low = mid + 1;
        else
            high = mid - 1;

即碰到target就返回,每次进行两次判断。

但是判断

if(A[mid] == target)

在开始时几乎没有意义,因为直接找到的可能性很小,为1/n。只有在后续的小区间判断,比较有意义。具体解释如下《代码之美》:

我们先来考虑循环的执行步骤。假设我们有一个有着 n 个元素的数组(此处n是一个很大的数值),那么从该数组中第一次找到目标的概率为 1/n(一个很小的数值),下一次(经过一次二分)的概率则是 1/(n/2)——仍然不是很大——以此类推下去。事实上,只有当元素的个数减少到了 10 到 20 的时候,一次找到目标的概率才变得有意义,而对于10 到 20 个元素进行查找需要的只是大概 4 次循环。当查找失败时(在大多数的应用中很普遍),那些额外的测试就将变成纯粹的额外开销。

我们也可以来计算一下,在什么时候找到目标值的概率能接近 50%,但请你扪心自问:在一个复杂度为 O(log2N)
的算法中,对于它的每一步都增添一个额外的复杂计算,而目的仅仅是为了减少最后的几次计算,这样做有意义吗?

所以,查找过程中可以将判断改为:

        if (A[mid] < target)
            low = mid + 1;
        else
            high = mid;

或者

        if (A[mid] > target)
            high = mid - 1;
        else
            low = mid;

这种查找还可以完成查找首个,或者最后一个出现的target。

int binary_search_first_position(int *A, int n, int target)  
{   
    int low = -1, high = n;
    assert(A != NULL && n >= 0);
    while (low + 1 < high)
    {
        int mid = low + (high - low) / 2;
        if (A[mid] < target)
            low = mid;
        else
            high = mid;
    }

    if (high >= n || A[high] != target)
        return -high - 1;
    else
        return high;  // high == low + 1
}

int binary_search_last_position(int *A, int n, int target)  
{
    int low = -1, high = n;
    assert(A != NULL && n >= 0);
    while (low + 1 < high)
    {
        int mid = low + (high - low) / 2;
        if (A[mid] > target)
            high = mid;
        else
            low = mid;
    }

    if (low < 0 || A[low] != target)
        return -low - 2;
    else
        return low;  // low == high - 1
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章