二分查找算法的遞歸、循環實現及其缺陷

關於二分查找法

      在學習算法的過程中,我們除了要了解某個算法的基本原理、實現方式,更重要的一個環節是分析算法的複雜度。在時間複雜度和空間複雜度之間,我們又會更注重時間複雜度,往往用犧牲空間換時間的方法提高時間效率。

時間複雜度按優劣排差不多集中在:

O(1), O(log n), O(n), O(n log n), O(n2), O(nk), O(2n)

二分查找法主要是解決在“一堆數中找出指定的數”這類問題,而想要應用二分查找法,這“一堆數”必須有一下特徵:

  • 存儲在數組中

  • 有序排列

所以如果是用鏈表存儲的,就無法在其上應用二分查找法了。

至於是順序遞增排列還是遞減排列,數組中是否存在相同的元素都不要緊。不過一般情況,我們還是希望並假設數組是遞增排列,數組中的元素互不相同

二分查找程序實現:

#include<iostream>

using namespace std;


//while循環實現

int Binary_Search1(int array[], int n, int value)

{

int left = 0;

int right = n-1;

while (left <= right)//注意這裏是"<="還是"=",若爲"=",則循環裏改爲right = middle 

{

int middle = left + ((right - left) >> 2);//直接平均可能會溢位,所以用此算法

if (array[middle] > value)

{

right = middle - 1;

}

else if(array[middle] < value)

{

left = middle + 1;

}

else

{

return middle;

}

}

return -1;

}



//遞歸實現

int Binary_Search2(int array[], int left,int right, int value)

{

if (left > right)//二分查找要有序

{

return -1;

}

int middle = left + ((right - left) >> 2);//直接平均可能會溢位,所以用此算法

if (array[middle] > value)

{

return Binary_Search2(array, left, middle - 1, value);

}

else if (array[middle] < value)

{

return Binary_Search2(array, middle + 1, right, value);

}

else

{

return middle;

}

}



int main()

{

int array[10] = { 1,2,3,5,7,8,9,11,13,45 };

int n = 0, num = 0,ret=0;

n = sizeof(array);

/*int left = 0, right = n-1;*/

cin >> num;

ret = Binary_Search1(array, n, num);

/*ret = Binary_Search2(array, left,right, num);*/

if (ret == -1)

{

cout << "查找失敗!"<< endl;

}

else

{

cout << num << "是第" << ret + 1 << "個數" << endl;

}

system("pause");

return 0;

}

運行結果1:

8

8是第6個數

請按任意鍵繼續. . .


運行結果2:

17

查找失敗!

請按任意鍵繼續. . .


二分查找法的缺陷

二分查找法的O(log n)讓它成爲十分高效的算法。不過它的缺陷卻也是那麼明顯的。就在它的限定之上:

     必有序,我們很難保證我們的數組都是有序的。當然可以在構建數組的時候進行排序,可是又落到了第二個瓶頸上:它必須是數組數組讀取效率是O(1),可是它的插入和刪除某個元素的效率卻是O(n)。因而導致構建有序數組變成低效的事情。

       解決這些缺陷問題更好的方法應該是使用二叉查找樹了,最好自然是自平衡二叉查找樹了,高效的(O(n logn))構建有序元素集合,又能如同二分查找法一樣快速(O(log n))的搜尋目標數。


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