二分查詢演算法

2021-06-19 22:42:47 字數 3389 閱讀 7863

折半查詢演算法也稱二分查詢演算法或折半搜尋演算法,是一種在有序陣列(即前提必須是陣列是已經排好序的)中查詢某一特定元素的搜尋演算法。搜素過程是

1)計算中間元素mid

從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜素過程結束;

2)比較左邊元素left, 比較右邊元素right

如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢,而且跟開始一樣從中間元素開始比較。如果在某一步驟陣列為空,則代表找不到。

這種搜尋演算法每一次比較都使搜尋範圍縮小一半。如下圖,lowerbound代表查詢起始範圍,upperbound代表查詢終止位置,mid是中間元素。我們需要考慮的是演算法何時結束?

我們定義如下的乙個函式來實現二分查詢

/ * @param a 待查詢的陣列 

* @param fromindex 查詢的起始位置

* @param toindex 查詢的終止位置是(toindex-1)

* @param key 要查詢的資料

* @return 查詢資料在陣列中的位置

* 如果查詢的資料不存在,則返回 - 1 * insertion point是查詢資料如果插入陣列時它插入的位置 */

public static int search(int a,int fromindex,int toindex,int key)

1) **第一次實現如下

觀察上述**,你能發現幾個問題呢?

1)輸入控制

如果陣列為null,那麼a[i]勢必會丟擲異常;

如果輸入的fromindex>toindex,函式本身就沒有意義;而且fromindex和toindex如果不在陣列長度範圍(0~length-1)內怎麼辦?

上述可能出現的異常,都源於沒有對輸入引數做控制處理。

//input control

if(a==null) //if a is null

return -1;

if(fromindex<0 || toindex>a.length-1 || fromindex>toindex)

throw new exception("illegal input!");

2)注意到while迴圈裡面mid沒有?在keya[mid]之前,a[mid]已和key比較過,能進行keya[mid],說明a[mid]肯定是和key不相等,所以後面沒有必要再比較mid了,修改如下

3)注意到while迴圈沒有迴圈結束的條件,這是致命的。那麼什麼時候二分查詢結束呢?

注意到進入下一次二分查詢改變的地方是upperbound=mid-1和lowerbound=mid+1,所以在這裡我們考慮臨界條件發生的情況。如果二分後還有2個元素時,我們記為i,i+1,那麼mid=(2i+1)/2=i,那麼分為2半(i,upperbound=mid-1=i-1)(lowerbound=mid+1=i+1,i+1)

如果是(i,upperbound=mid-1=i-1),那麼再做一次劃分就會出現lowerbound>upperbound的異常;

如果是(lowerbound=mid+1=i+1,i+1),那麼再做一次劃分也會出現lowerbound>upperbound;

所以迴圈結束的條件是陣列中只剩2個元素時,直接折半查詢每次把查詢範圍砍掉一半,最後當只有乙個元素時(此時lowerbound=upperbound),經過語句upperbound=mid-1或lowerbound=mid+1後,lowerbound>upperbound,此時迴圈結束。所以臨界條件(base case)是lowerbound>upperbound,此時停止查詢。

package zyang.binaryinsertsort;

/**

* @version 1.0

* @date 2012-11-14 上午10:03:59

* @fuction binary search

* binary search

* 折半搜尋,也稱二分查詢演算法、二分搜尋,是一種在有序陣列中查詢某一特定元素的搜尋演算法。

* 搜素過程從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜素過程結束;

* 如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢,而且跟開始一樣從中間元素開始比較。

* 如果在某一步驟查詢的陣列的下界大於上屆,則代表找不到。這種搜尋演算法每一次比較都使搜尋範圍縮小一半。

* 時間複雜度:二分搜尋每次把搜尋區域砍掉一半,很明顯時間複雜度為o(logn)。(n代表集合中元素的個數)

* 空間複雜度:o(1)

*/public class binarysearch

/*** 根據給定陣列下標的範圍,用折半查詢演算法查詢指定資料

* 陣列必須是已排好序的,否則查詢結果沒有意義。如果陣列中有相等的元素,則會找到其中之一,至於是哪乙個,是不確定的

* @param a 待查詢的陣列

* @param fromindex 查詢的起始位置

* @param toindex 查詢的終止位置

* @param key 要查詢的資料

* @return 查詢資料在陣列中的位置

* 如果查詢的資料不存在,則返回(- 1)

* insertion point是查詢資料如果插入陣列時它插入的位置

* @throws exception

*///implement by loop

public static int search(int a,int fromindex,int toindex,int key) throws exception

; }}

折半查詢的邊界條件

折半查詢每次把查詢範圍砍掉一半,最後當只有乙個元素時(此時lowerbound=upperbound),經過語句upperbound=mid-1或lowerbound=mid+1後,lowerbound>upperbound,此時迴圈結束。所以臨界條件(base case)是lowerbound>upperbound,此時停止查詢。

時間複雜度

折半查詢每次把搜尋區域砍掉一半,很明顯時間複雜度為

空間複雜度

查詢演算法 二分查詢

利用二分查詢演算法查詢某乙個元素,前提條件是該被查詢的元素是乙個已經有序的陣列。二分查詢的思想是將陣列元素的最高位 high 和最低位 low 進行標記,取陣列元素的中間 mid 和和要查詢的值 key 進行比較,如果目標值比中間值要大,則將最低位設定為mid 1,繼續進行查詢。如果目標值小於中間值...

查詢演算法 二分查詢

二分查詢的思路是很簡單的,前提是這組資料是有順序的。思路是從中間找乙個數,判斷大小,如果數比中間數大,說明在中間數到結尾的數中,如果小於,則說明在開始和中間數之間,經過多次相同操作,就可以得到我們想查詢的數時間複雜度就是 o logn 非遞迴的實現 const testarr let i 0whil...

查詢演算法 二分查詢

二分查詢是乙個常用的查詢演算法,其原理在於通過不斷切分乙個規則排序,對半的去尋找目標元素所在的區間與位置。但是其有乙個前提,那就是資料結構需要是順序儲存結構,並且關鍵字大小有序排列。例子如下 例 有乙個數列 12,23,45,56,67,89 請使用二分查詢找到56的位置 解 首先mid 0 5 2...