1. 程式人生 > >Binary Search 的遞迴與迭代實現及STL中的搜尋相關內容

Binary Search 的遞迴與迭代實現及STL中的搜尋相關內容

與排序演算法不同,搜尋演算法是比較統一的,常用的搜尋除hash外僅有兩種,包括不需要排序的線性搜尋和需要排序的binary search。

首先介紹一下binary search,其原理很直接,不斷地選取有序陣列的組中值,比較組中值與目標的大小,繼續搜尋目標所在的一半,直到找到目標,遞迴演算法可以很直觀的表現這個描述:

int binarySearchRecursive(int A[], int low, int high, int key)
{
    if (low > high) return -1;
    int mid = (low + high) >> 1;
    if (key < A[mid]) return binarySearchRecursive(A, low, mid - 1, key);
    
else if (key > A[mid]) return binarySearchRecursive(A, mid + 1, high, key); else return mid; }

但實際上,遞迴方法的時間效率和空間效率都不如迭代方法,迭代方法才是常用的binary search,程式碼如下:

int binarySearch(int A[], int low, int high, int key)
{
    int mid;
    while (low <= high)
    {
        mid = (low + high) >> 1
; if (key < A[mid]) high = mid - 1; else if (key > A[mid]) low = mid + 1; else return mid; } return -1; }

簡單計算一下Binary Search的效率:

演算法流程:

1.檢查上下邊界--2.獲取中值--3.比較--左半邊進入子問題/右半邊進入自問題/獲得結果

1,2所需時間為常數時間,設為C。3階段以一半的資料量重新執行函式,所以:

T(n)=T(n/2)+C

設n=2^k,則有T(2^k)=T(2^(k-1))+C=(T(2^(k-2))+C)+C=T(1)+k*C

即T(n)=log(n)*C+T(1),所以binary search是一個O(log(n))的演算法。

測試函式:

void searchTest()
{
    int a[] = { 1,2,3,4,5,7,9,11,17,20,23,39 };
    cout << binarySearch(a, 0, 11, 39) << endl;
    cout << binarySearch(a, 0, 11, 37) << endl;
    cout << binarySearch(a, 5, 10, 39) << endl;
    cout << endl;
    cout << binarySearchRecursive(a, 0, 11, 39) << endl;
    cout << binarySearchRecursive(a, 0, 11, 37) << endl;
    cout << binarySearchRecursive(a, 5, 10, 39) << endl;
}

測試結果如下:

11
-1
-1

11
-1
-1
請按任意鍵繼續. . .

傳統C函式中有bsearch這一函式,因為在現代C++中使用C庫執行效率很低,加上介面並不好用,不再提及。而STL中,有以下幾個關於搜尋的函式。他們均作用於各個STL容器。

int count(起始迭代器,終止迭代器,key value)

return key value的數量

iterator find(起始迭代器,終止迭代器,key value)

成功:return 找到的第一個key value的迭代器

失敗:return 終止迭代器

bool binary_search(起始迭代器,終止迭代器,key value)

return 是否找到

iterator lower_bound(起始迭代器,終止迭代器,key value)

return 大於或等於key value的第一個迭代器,若所有值都小於key value,返回終止迭代器

iterator upper_bound(起始迭代器,終止迭代器,key value)

return 大於key value的第一個迭代器,若所有值都小於key value,返回終止迭代器

這些函式中,count和find是作用於任意排序物件的,其效率為O(n),而binary_search, lower_bound, upper_bound是作用於有序物件的,其效率是O(logN)。

下面程式碼給出這些STL函式的測試:

void searchTest()
{
    vector<int> b{ 1,2,3,4,4,7,9,11,17,20,23,39 };
    cout << "vector<int> b{ 1,2,3,4,4,7,9,11,17,20,23,39 };" << endl;
    cout << "count(b.begin(), b.end(), 4):"
        << count(b.begin(), b.end(), 4) << endl;
    cout << endl;
    cout << "find(b.begin(), b.end(), 39) - b.begin():"
        << find(b.begin(), b.end(), 39) - b.begin() << endl;
    cout << "find(b.begin(), b.end(), 4) - b.begin():"
        << find(b.begin(), b.end(), 4) - b.begin() << endl;
    cout << "find(b.begin(), b.end(), 37) - b.begin():"
        << find(b.begin(), b.end(), 37) - b.begin() << endl;
    cout << "find(b.begin() + 5, b.begin() + 10, 39) - b.begin():"
        << find(b.begin() + 5, b.begin() + 10, 39) - b.begin() << endl;
    cout << endl;
    cout << "binary_search(b.begin(), b.end(), 39):"
        << binary_search(b.begin(), b.end(), 39) << endl;
    cout << "binary_search(b.begin(), b.end(), 37):"
        << binary_search(b.begin(), b.end(), 37) << endl;
    cout << endl;
    cout << "lower_bound(b.begin(), b.end(), 39) - b.begin():"
        << lower_bound(b.begin(), b.end(), 39) - b.begin() << endl;
    cout << "lower_bound(b.begin(), b.end(), 4) - b.begin():"
        << lower_bound(b.begin(), b.end(), 4) - b.begin() << endl;
    cout << "lower_bound(b.begin(), b.end(), 37) - b.begin():"
        << lower_bound(b.begin(), b.end(), 37) - b.begin() << endl;
    cout << "lower_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():"
        << lower_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin() << endl;
    cout << endl;
    cout << "upper_bound(b.begin(), b.end(), 39) - b.begin():"
        << upper_bound(b.begin(), b.end(), 39) - b.begin() << endl;
    cout << "upper_bound(b.begin(), b.end(), 4) - b.begin():"
        << upper_bound(b.begin(), b.end(), 4) - b.begin() << endl;
    cout << "upper_bound(b.begin(), b.end(), 37) - b.begin():"
        << upper_bound(b.begin(), b.end(), 37) - b.begin() << endl;
    cout << "upper_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():"
        << upper_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin() << endl;
}

測試結果:

vector<int> b{ 1,2,3,4,4,7,9,11,17,20,23,39 };
count(b.begin(), b.end(), 4):2

find(b.begin(), b.end(), 39) - b.begin():11
find(b.begin(), b.end(), 4) - b.begin():3
find(b.begin(), b.end(), 37) - b.begin():12
find(b.begin() + 5, b.begin() + 10, 39) - b.begin():10

binary_search(b.begin(), b.end(), 39):1
binary_search(b.begin(), b.end(), 37):0

lower_bound(b.begin(), b.end(), 39) - b.begin():11
lower_bound(b.begin(), b.end(), 4) - b.begin():3
lower_bound(b.begin(), b.end(), 37) - b.begin():11
lower_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():10

upper_bound(b.begin(), b.end(), 39) - b.begin():12
upper_bound(b.begin(), b.end(), 4) - b.begin():5
upper_bound(b.begin(), b.end(), 37) - b.begin():11
upper_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():10
請按任意鍵繼續. . .