【注】二分查詢的前提是有序向量,亦或有序線性表
template
<
typename t>
// 查詢演算法同一介面,0 <= lo < hi <= _size
rank vector
::search
(t const
&e, rank lo, rank hi)
const
應該便於有序向量自身的維護:v.insert(1 + v.search(e), e)
即便失敗,也應給出新元素適當的插入位置
若允許重複元素,則每一組也需按其插入的次序排列
【約定】
減而治之:以任一元素x = s[mi]
為界,都可將待查詢區間分為三部分,s[lo, mi) <= s[mi] <= s(mi, hi)
只需將目標元素 e 與 x 做一比較,即可分三種情況進一步處理:
1、e < x
:則 e 若存在必屬於左側
子區間s[lo, mi)
,故可遞迴深入
2、x < e
:則 e 若存在必屬於右側
子區間s(mi, hi)
,亦可遞迴深入
3、e = x
:已在此處命中,可隨即返回
二分(折半)策略:軸點 mi 總是取作中點 —— 於是每經過至多兩次
比較,或者能夠命中,或者將問題規模縮減一半
template
<
typename t>
// 在有序向量區間 [lo, hi) 內查詢元素 e
static rank binsearch
(t *a, t const
&e, rank lo, rank hi)
return-1
;// 查詢失敗
}
s.search(8, 0, 7)
:共經 2 + 1 + 2 = 5 次比較,在s[4]
處命中
s.search(3, 0, 7)
:共經 1 + 1 + 2 = 4 次比較,在s[1]
處失敗
線性遞迴:t(n) = t(n/2) + o(1) = o(logn)
,大大優於順序查詢
遞迴跟蹤:軸點總取中點,遞迴深度o(logn)
;各遞迴例項均耗時o(1)
如何更為精細地評估查詢演算法地效能?
考查關鍵碼地比較次數,即查詢長度(search length)
通常,需分別針對成功與失敗查詢,從最好、最壞、平均等角度評估
比如,成功、失敗時地平均查詢長度均大致為o(1.50 * logn)
直接解決
二分查詢中左、右分支轉向代價不平衡的問題
比如,每次迭代(或每個遞迴例項)僅做1次
關鍵碼比較
如此,所有分支只有2個
方向,而不再是3個
同樣的,軸點mi
取作中點,則查詢每深入一層,問題規模也縮減一半
1、e < x
:則e
若存在必屬於左側子區間s[lo, mi)
,故可遞迴深入
2、x <= e
:則e
若存在必屬於右側子區間s[mi, hi)
,亦可遞迴深入
只有當元素數目hi - lo = 1
時,才判斷該元素是否命中
template
<
typename t>
static rank binsearch
(t *a, t const
&e, rank lo, rank hi)
// 出口時 hi = lo + 1,查詢區間僅含乙個元素 a[lo]
return
(e == a[lo]
)? lo :-1
;// 返回命中 or -1
}// 相對於版本a,最好(壞)情況下更壞(好);各種情況下的 sl 更加接近,整體效能更趨穩定
以上二分查詢演算法
未嚴格兌現search()
介面的語義約定:返回不大於 e 的最後乙個元素
1、當有多個命中元素時,必須返回最靠後(秩最大)者
2、失敗時,應返回小於 e 的最大者(含哨兵[lo - 1])
template
<
typename t>
static rank binsearch
(t *a, t const
&e, rank lo, rank hi)
// 出口時, a[lo = hi] 為大於 e 的最小元素
return
--lo;
// 故 lo - 1 即不大於 e 的元素的最大秩
}
1、待查詢區間寬度縮短至0
而非1
時,演算法才結束
2、轉入右側子向量時,左邊界取作mi + 1
而非mi
3、無論成功與否,返回的秩嚴格符合介面的語義
不變性:a[0, lo) <= e < a[hi, n)
,a[hi]
總是大於 e 的最小者
初始時,$ lo = 0 且 hi = n,a[0, lo) = a[hi, n) = \emptyset $,自然成立
數學歸納:假設不變性一直保持至(a),以下無非兩種情況 …
資料結構基礎 5 二分查詢
include include include include int binary serch int arr,int arr len,int value else if value arr m else return 1 int main int argc,char argv for pos 0...
c 資料結構與演算法 5 二分查詢
include include includeusing namespace std 二分查詢 int binarysearch int array,const int n,const int search 選擇排序 void selectsort int array,int n int main ...
資料結構 二分查詢
二分查詢演算法也稱為折半搜尋 二分搜尋,是一種在有序陣列中查詢某一特定元素的搜尋演算法。搜素過程從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜素過程結束 如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢,而且跟開始一樣從中間元素開始比較。如果在某一步驟陣列為...