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
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章