二分查詢演算法基本思想
二分查詢演算法的前置條件是,乙個已經排序好的序列(在本篇文章中為了說明問題的方便,假設這個序列是公升序排列的),這樣在查詢所要查詢的元素時,首先與序列中間的元素進行比較,如果大於這個元素,就在當前序列的後半部分繼續查詢,如果小於這個元素,就在當前序列的前半部分繼續查詢,直到找到相同的元素,或者所查詢的序列範圍為空為止.
用偽**來表示, 二分查詢演算法大致是這個樣子的:
left =0
, right =n
-1while
(left
<=
right)
mid
=(left
+right) /2
case
x[mid]
<
t: left
=mid +1
;x[mid]
=t: p
=mid;
break
;x[mid]
>
t: right
=mid -1
;return-1
; 第乙個正確的程式
根據前面給出的演算法思想和偽**, 我們給出第乙個正確的程式,但是,它還有一些小的問題,後面會講到
intsearch(
intarray,
intn,
intv)
else
if(array[middle]
<
v)else
}return-1
;}
下面,講講在編寫二分查詢演算法時可能出現的一些問題.
邊界錯誤造成的問題
二分查詢演算法的邊界,一般來說分兩種情況,一種是左閉右開區間,類似於[left, right),一種是左閉右閉區間,類似於[left, right].需要注意的是, 迴圈體外的初始化條件,與迴圈體內的迭代步驟, 都必須遵守一致的區間規則,也就是說,如果迴圈體初始化時,是以左閉右開區間為邊界的,那麼迴圈體內部的迭代也應該如此.如果兩者不一致,會造成程式的錯誤.比如下面就是錯誤的二分查詢演算法:
intsearch_bad(
intarray,
intn,
intv)
else
if(array[middle]
<
v)else
}return-1
;}
這個演算法的錯誤在於, 在迴圈初始化的時候,初始化right=n,也就是採用的是左閉右開區間,而當滿足array[middle] > v的條件是, v如果存在的話應該在[left, middle)區間中,但是這裡卻把right賦值為middle - 1了,這樣,如果恰巧middle-1就是查詢的元素,那麼就會找不到這個元素.
下面給出兩個演算法, 分別是正確的左閉右閉和左閉右開區間演算法,可以與上面的進行比較:
intsearch2(
intarray,
intn,
intv)
else
if(array[middle]
<
v)else
}return-1
;}intsearch3(
intarray,
intn,
intv)
else
if(array[middle]
<
v)else
}return-1
;}
死迴圈上面的情況還只是把邊界的其中乙個寫錯, 也就是右邊的邊界值寫錯, 如果兩者同時都寫錯的話,可能會造成死迴圈,比如下面的這個程式:
intsearch_bad2(
intarray,
intn,
intv)
else
if(array[middle]
<
v)else
}return-1
;}
這個程式採用的是左閉右閉的區間.但是,當array[middle] > v的時候,那麼下一次查詢的區間應該為[middle + 1, right], 而這裡變成了[middle, right];當array[middle] < v的時候,那麼下一次查詢的區間應該為[left, middle - 1], 而這裡變成了[left, middle].兩個邊界的選擇都出現了問題, 因此,有可能出現某次查詢時始終在這兩個範圍中輪換,造成了程式的死迴圈.
溢位前面解決了邊界選擇時可能出現的問題, 下面來解決另乙個問題,其實這個問題嚴格的說不屬於演算法問題,不過我注意到很多地方都沒有提到,我覺得還是提一下比較好.
在迴圈體內,計算中間位置的時候,使用的是這個表示式:
middle
=(left
+right) /2
; 假如,left與right之和超過了所在型別的表示範圍的話,那麼middle就不會得到正確的值.
所以,更穩妥的做法應該是這樣的:
middle
=left
+(right
-left) /2
; 更完善的演算法
前面我們說了,給出的第乙個演算法是乙個"正確"的程式, 但是還有一些小的問題.
首先, 如果序列中有多個相同的元素時,查詢的時候不見得每次都會返回第乙個元素的位置, 比如考慮一種極端情況:序列中都只有乙個相同的元素,那麼去查詢這個元素時,顯然返回的是中間元素的位置.
其次, 前面給出的演算法中,每次迴圈體中都有三次情況,兩次比較,有沒有辦法減少比較的數量進一步的優化程式?
《程式設計珠璣》中給出了解決這兩個問題的演算法,結合前面提到溢位問題我對middle的計算也做了修改:
intsearch4(
intarray,
intn,
intv)
else}if
(right
>=
n ||
array[right]
!=v)
return
right;}
這個演算法是所有這裡給出的演算法中最完善的乙個,正確,精確且效率高.
經典演算法 二分查詢
二分查詢這種老生常談的話題,說的很簡單,但是仍然有些大夥不明白,所以這裡希望自己能夠寫出一篇很淺顯易懂的部落格幫助大家理解 給定陣列已經排序好,然後對其進行編號。這裡我們預設是從小到大的,否則演算法就要進行更改了 思想 因為陣列是有序的,所以每次和陣列中間的乙個比較,通過和其大小的關係,然後再折半比...
經典演算法 二分查詢
題目說明 二分查詢法是對一組有序的數字中進行查詢,傳遞相應的資料,進行比較查詢到與原資料相同的資料,查詢到了返回對應的陣列下標,失敗返回 1。題目解析 二分查詢又稱折半查詢,優點是比較次數少,查詢速度快,平均效能好 其缺點是要求待查表為有序表,且插入刪除困難。因此,折半查詢方法適用於不經常變動而查詢...
二分查詢演算法1
include 二分查詢法一 using namespace std int binary search int b,int value,int n 9 int hight 9,low 0,mid while hight low 注意兩者相等的情況 mid hight low 2 if value ...