二分查詢(binary search)
二分查詢(binary search)
二分查詢對於學過資料結構或者演算法的人來說,應該是非常熟悉的。其基本思想是:比較目標(target)和中間關鍵字的大小關係,如果二者相等,則查詢完畢;如果二者不等,則可以根據二者的大小關係,將查詢的範圍減半。
雖然二分查詢的演算法很簡單,但是對於一個code新手來說,正確無誤地實現一個二分查詢演算法也不是那麼容易的。
最近,刷了幾道二分查詢的題目,將刷題的一點收穫整理如下:
1.二分查詢演算法適用的範圍:
①必須是順序表,不適用於鏈式儲存
②查詢之前,序列必須是有序的。對於無序的序列,可以先採用合適的排序演算法進行排序後,再使用二分查詢。
2.二分查詢演算法的基本模式:
遞迴方式:
int binary_search(const int[] arr,int start,int end,int khey){
if(start > end)
return -1;
int mid = start + (end - start) / 2;
if(arr[mid] > khey)
return binary_search(arr,start,mid-1,khey);
if(arr[mid] < khey)
return binary_search(arr,mid+1 ,end,khey);
return mid;//最後檢測相等是因為大多數情況下是小於或者大於
}
非遞迴方式:(更常用)
int binary_search(const int[] arr,int start,int end,int khey){
int mid;
while(start <= end){
mid = start + (end - start) / 2;
if(arr[mid] < khey)
start = mid +1;
else if(arr[mid] > khey)
end = mid - 1 ;
else
return mid;
}
return -1;
}
其中,需要注意的地方有:
① 我們學習二分演算法的時候,求mid可能會用:mid = (start + end)/2,這時,在計算start+end的時候,可能會產生溢位,故以上所寫的兩種方式,均採用start + (end - start) / 2的方式,有時候可以避免溢位。
②在非遞迴演算法中,while迴圈中究竟應該是(start < end)還是(start <= end),這應該具體情況具體分析;
③對於mid和khey比較的三種情況(大於,小於,相等)的排列順序,大多數情況下,是影響不大的,實際中,可以根據三種情況出現的概率,決定其順序;
④以上僅僅是二分查詢演算法的模板,具體使用時應該具體情況具體分析,靈活運用。
3.二分查詢的複雜度
時間複雜度:O(logn)
空間複雜度:O(1)
在有些地方你可能會看到三分查詢(ternary search),三分查詢基本思想和二分查詢一致,具體來講:每次選出三分之一點和三分之二點,而不是中點,然後比較target和這兩個點的大小關係,從而將查詢的範圍縮小至原來的三分之一。
二分查詢和三分查詢的空間複雜度都是O(1),而二分查詢的時間複雜度是O(log2n),三分查詢的時間複雜度是O(log3n)。既然三分查詢的時間複雜度要優於二分查詢,那我們為什麼不經常使用三分查詢,而經常使用二分查詢呢?原因在於在最壞情況下,三分查詢要明顯劣於二分查詢。這個具體的推導過程就不詳述了, 想了解的可以參考這道題目。