1. 程式人生 > >005-二分搜尋-分治法-《演算法設計技巧與分析》M.H.A學習筆記

005-二分搜尋-分治法-《演算法設計技巧與分析》M.H.A學習筆記

二分搜尋又稱折半查詢,用於在排序好的序列表中進行搜尋,搜尋效率高,可在最壞的情況下用O(log n)完成搜尋任務

基本思想:

n個元素分成個數大致相同的兩半,取a[n/2]與欲查詢的x作比較,如果x=a[n/2]則找到x,演算法終止。如 果x<a[n/2],則我們只要在陣列a的左半部繼續搜尋x(這裡假設陣列元素呈升序排列)。如果x>a[n/2],則我們只要在陣列a的右 半部繼續搜尋x

虛擬碼:

 

C++程式碼:

  1. int binSearch(constint *Array,int start,int end,int key)  
  2. {  
  3.     int left,right;  
  4.     int mid;  
  5.     left=start;  
  6.     right=end;  
  7.     while(left<=right)  
  8.     {  
  9.         mid=(left+right)/2;  
  10.         if(key==Array[mid])  return mid;  
  11.         elseif(key<Array[mid]) right=mid-1;  
  12.         elseif(key>Array[mid]) left=mid+1;  
  13.     }  
  14.     return -1;  
  15.     //找不到就返回-1
  16. }  


“最小化最大值”:

這一演算法運用在stl的兩個函式中:

lower_bound

給定長度為n的單調不下降數列a0,a1,…,an−1和一個數k,求滿足ai≥k條件的最小的i。不存在的情況下輸出 n。

upper_bound

給定長度為n的單調不下降數列a0,a1,…,an−1和一個數k,求滿足ai >k條件的最小的i。不存在的情況下輸出 n。

C++程式碼:

兩種寫法(區別在判斷截止的條件,本質上並沒有分別):

1.

  1. while( rb > lb )  
  2. {       
  3. int m = (lb + rb) / 2;  
  4. if( ok(m) ) rb = m;  
  5. else lb = m + 1;  
  6. }  
  7. // 答案為: lb == rb

2.

  1. while( rb - lb > 1 )  
  2. {     
  3. int m = (lb + rb) / 2;      
  4.  if( ok(m) ) rb = m;      
  5. else lb = m;  
  6. }  
  7. // 跳出迴圈時 lb + 1 == rb
  8. // 答案為 rb<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

貼兩個常用的程式碼:

  1. // 在arr的[sl, sr)下標範圍內查詢左起第一個>=target的元素,找到返
  2. // 回所在下標, 否則返回sr(區間最右元素下標+1)
  3. int LowerBound(int *arr, int sl, int sr, int target) {  
  4.       int l = sl, r = sr - 1, mid;  
  5.       while (l <= r) {  
  6.              mid = (l +r) >>1;  
  7. if (arr[mid] < target) l = mid + 1;  
  8.              else r = mid;  
  9.       }  
  10.       return (l == r ? r : sr);  
  11. }  

  1. // 在arr的[sl, sr)下標範圍內查詢左起第一個>target的元素,找到返
  2. // 回所在下標, 否則返回sr(區間最右元素下標+1)
  3. int UpperBound(int *arr, int sl, int sr, int target) {  
  4.       int l = sl, r = sr - 1, mid;  
  5.       while (l <= r) {  
  6.              mid = (l +r) >>1;  
  7. if (arr[mid] <= target) l = mid + 1;  
  8.              else r = mid;  
  9.       }  
  10.       return (l == r ? r : sr);  
  11. }  


浮點數的二分搜尋

關鍵在於截止條件,我們需要比較的是兩個數的接近程度而不是大小abs(l-r)>=1e-10,當然我們可以直接指定迴圈次數,如100次,可以達到21001030 的精度範圍。

二分搜尋的演算法分析:

書中這一段寫得很清楚,就直接截圖了:

 

這裡的j就是搜尋樹的高度,即查詢的複雜度為O(log n)。