二分查找又稱為折半查找,僅適用於事先已經排好序的順序表。其查找的基本思路:首先將給定值K,與表中中間位置元素的關鍵字比較,若相等,返回該元素的存儲位置;若不等,這所需查找的元素只能在中間數據以外的前半部分或后半部分中。然后在縮小的范圍中繼續進行同樣的查找。如此反復直到找到為止。算法如下:
1 template<typename T> 2 int BinarySearch(vector<T> &data, T key) { 3 int low = 0, high = data.size() - 1; 4 while (low <= high) { 5 int mid = low + (high - low) / 2; 6 if (data[mid] == key) { 7 return mid; 8 } else if (data[mid] > key) { 9 high = mid - 1; 10 } else { 11 low = mid + 1; 12 } 13 } 14 15 return -1; 16 }
因為二分查找需要方便地定位查找區域,所以適合二分查找的存儲結構必須具有隨機存儲的特性。因此,該查找方法僅適合於線性表的順序存儲結構,不適合鏈式存儲結構,且要求元素按關鍵字有序排列。
判定樹:
二分查找的過程可以用下圖表示,稱為判定樹。樹中每個圓形節點表示一個紀錄,節點中的值表示為該記錄的關鍵字值:樹中最下面葉節點都是方形的,它表示查找不成功的情況。從判定樹中可以看出,查找成功時查找的查找長度為從根節點到目的節點的路徑上的節點數,而查找不成功時的查找長度為從根節點到對應失敗節點的父節點的父節點路徑上的節點數;每個節點值均大於其左子節點值,且均小於右子節點值。若有序序列有n個元素,這對應的判定樹有n個圓形的非葉節點和n+1個方形的葉節點。
上圖中,n個圓形節點(代表有序序列有n個元素)構成的樹的深度與n個節點完全二叉樹的深度(高度)相等,均為⌊log2n⌋+1或⌈log2(n+1)⌉
二分查找的時間復雜度為O(log2N),比順序查找的效率高。
由上述分析可知,用二分查找到給定值或查找失敗的比較次數最多不會超過樹的高度。查找成功與不成功,最壞的情況下,都需要比較⌊log2n⌋+1次。
二分查找的優點和缺點
雖然二分查找的效率高,但是要將表按關鍵字排序。而排序本身是一種很費時的運算。既使采用高效率的排序方法也要花費O(nlgn)的時間。
二分查找只適用順序存儲結構。為保持表的有序性,在順序結構里插入和刪除都必須移動大量的結點。因此,二分查找特別適用於那種一經建立就很少改動、而又經常需要查找的線性表。
對那些查找少而又經常需要改動的線性表,可采用鏈表作存儲結構,進行順序查找。鏈表上無法實現二分查找。
相關題目:
1. [LeetCode] Search in Rotated Array
2. [LeetCode] Search in Rotated Array II
4.《劍指offer》面試題3、面試題8
相關資料:
1.http://www.zhihu.com/question/22422613
2.http://www.cppblog.com/converse/archive/2009/10/05/97905.html
3.http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binarySearch
4.http://www.cnblogs.com/bhlsheji/p/4211826.html
參考資料:
1.《王道程序員求職寶典》
2. http://student.zjzk.cn/course_ware/data_structure/web/chazhao/chazhao9.2.2.1.htm