二分查詢法

2021-07-31 01:44:09 字數 2896 閱讀 6911

二分查詢法主要是解決在「一堆數中找出指定的數」這類問題。

而想要應用二分查詢法,這「一堆數」必須有一下特徵:

所以如果是用鍊錶儲存的,就無法在其上應用二分查詢法了。(曽在面試被問二分查詢法可以什麼資料結構上使用:陣列?鍊錶?)

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

二分查詢法在演算法家族大類中屬於「分治法」,分治法基本都可以用遞迴來實現的,二分查詢法的遞迴實現如下:

int bsearch(int array, int low, int high, int target)

不過所有的遞迴都可以自行定義stack來解遞迴,所以二分查詢法也可以不用遞迴實現,而且它的非遞迴實現甚至可以不用棧,因為二分的遞迴其實是

尾遞迴,它不關心遞迴前的所有資訊。

int bsearchwithoutrecursion(int array, int low, int high, int target)

//the array does not contain the target

return -1;

}

之前的都是在陣列中找到乙個數要與目標相等,如果不存在則返回-1。我們也可以用二分查詢法找尋邊界值,也就是說在有序陣列中找到「正好大於(小於)目標數」的那個數。

用數學的表述方式就是:

在集合中找到乙個大於(小於)目標數t的數x,使得集合中的任意數要麼大於(小於)等於x,要麼小於(大於)等於t。

舉例來說:

給予陣列和目標數

int array = ;

int target = 7;

那麼上界值應該是11,因為它「剛剛好」大於7;下屆值則是5,因為它「剛剛好」小於7。

//find the fisrt element, whose value is larger than target, in a sorted array 

int bsearchupperbound(int array, int low, int high, int target)

return mid;

}

與精確查詢不同之處在於,精確查詢分成三類:大於小於等於(目標數)。而界限查詢則分成了兩類:大於不大於

如果當前找到的數大於目標數時,它可能就是我們要找的數,所以需要保留這個索引,也因此if (array[mid] > target)時 high=mid; 而沒有減1。

//find the last element, whose value is less than target, in a sorted array 

int bsearchlowerbound(int array, int low, int high, int target)

return mid;

}

下屆尋找基本與上屆相同,需要注意的是在取中間索引時,使用了向上取整。若同之前一樣使用向下取整,那麼當low == high-1,而array[low] 又小於 target時就會形成死迴圈。因為low無法往上爬超過high。

這兩個實現都是找嚴格界限,也就是要大於或者小於。如果要找鬆散界限,也就是找到大於等於或者小於等於的值(即包含自身),只要對**稍作修改就好了:

去掉判斷陣列邊界的等號:

target >= array[high]改為 target > array[high]
在與中間值的比較中加上等號:

array[mid] > target改為array[mid] >= target

之前我們使用二分查詢法時,都是基於陣列中的元素各不相同。假如存在重複資料,而陣列依然有序,那麼我們還是可以用二分查詢法判別目標數是否存在。不過,返回的index就只能是隨機的重複資料中的某乙個。

此時,我們會希望知道有多少個目標數存在。或者說我們希望陣列的區域。

結合前面的界限查詢,我們只要找到目標數的嚴格上屆和嚴格下屆,那麼界限之間(不包括界限)的資料就是目標數的區域了。

//return type: pair//the fisrt value indicate the begining of range,

//the second value indicate the end of range.

//if target is not find, (-1,-1) will be returned

pairsearchrange(int a, int n, int target)

它的時間複雜度是兩次二分查詢所用時間的和,也就是o(log n) + o(log n),最後還是o(log n)。

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

必須有序,我們很難保證我們的陣列都是有序的。當然可以在構建陣列的時候進行排序,可是又落到了第二個瓶頸上:它必須是陣列。

陣列讀取效率是o(1),可是它的插入和刪除某個元素的效率卻是o(n)。因而導致構建有序陣列變成低效的事情。

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

二分查詢法

二分查詢要求 1.必須採用順序儲存結構 2.必須按關鍵字大小有序排列。優缺點 折半查詢法的優點是比較次數少,查詢速度快,平均效能好 其缺點是要求待查表為有序表,且插入刪除困難。因此,折半查詢方法適用於不經常變動而查詢頻繁的有序列表。演算法思想 首先,將表中間位置記錄的關鍵字與查詢關鍵字比較,如果兩者...

二分查詢法

有序陣列中的find 方法 public int find long serchkey int lowerbound 0 int upperbound nelems 1 while true curin lowerbound upperbound 2 if a curin serchkey retu...

二分查詢法

演算法基本思想 二分查詢演算法的前置條件是,乙個已經排序好的序列 假設這個序列是公升序排列的 這樣在查詢所要查詢的元素時,首先與序列中間的元素進行比較,如果大於這個元素,就在當前序列的後半部分繼續查詢,如果小於這個元素,就在當前序列的前半部分繼續查詢,直到找到相同的元素,或者所查詢的序列範圍為空為止...