對於順序表中已經排好序的表來說,除了上篇文章中的可以比較大小外,還可以有另外一種思路,就是二分查詢。因為已經排好序了,可以直接比較中間值(中位數),如果中位數比要查詢的數大,那麼要查詢的數可能在前半部分(至少不可能在後半部分),因為後半部分一定比中位數大,也一定比要查詢的數大。繼續,把前半部分當做乙個新的有序表,進一步比較中位數,直到找到要查詢的數或者不存在。
def binary_search(alist, item):
first = 0
last = len(alist) - 1
mid = 0
found = false
while first <= last and not found:
mid = (first + last) // 2
if alist[mid] == item:
found = true
elif alist[mid] < item: # 說明item一定在當前列表的後半部分,所以篩選範圍向後移動
first = mid + 1
else:
last = mid - 1 # 一定在前半部分
if found:
return mid
else:
return false
# 注意列表一定是有序的。
testlist = [0,1,2,8,13,17,19,32,42]
print(binary_search(testlist, 32))
print(binary_search(testlist, 17))
當然也可以用遞迴的形式做,在前面敘述中可以看出來,每次分割後,都把要比較的子列表當做乙個新的列表進一步比較,其實這就是遞迴的過程。因為遞迴每次的變數都會重複,這裡如果要輸出要查詢元素的下標,需要注意。
# 二分查詢的遞迴形式
def binary_search(alist, item):
first = 0
last = len(alist) - 1
if first <= last:
mid = (first + last) // 2
if alist[mid] == item:
# 注意返回的mid是此時的first和last的中間值
return mid
elif alist[mid] < item:
# 注意,因為本函式中每次都是初始化first和last
# 所以遞迴呼叫時,返回的miid是當前子列表的中間值
# 要想得到原始的中間值,需要起始位置
first = mid + 1
return first + binary_search(alist[first:], item)
else:
# 此時的開始的相對位置沒有改變,改變的只是結束位置
# 而結束位置並不影響子列表的中間值的相對原來的位置
# 所以此處不需要加上起始位置first。
last = mid - 1
return binary_search(alist[:last+1], item)
else:
return false
testlist = [0,1,2,8,13,17,19,32,42]
print(binary_search(testlist, 13))
print(binary_search(testlist, 8))
接下來再看一下時間複雜度。每一次比較,那麼剩下的還需要比較的就是n/2個元素(最壞的情況下),做第二次比較時,還剩下n/4個元素,也就是n/(2^i)。
如果還剩乙個元素時,就只需要比較一次就知道結果了,所以n/(2^i)=1時就是最終結束時,可以看出來i=log(n),成對數形式的複雜度,比線性的複雜度要低一點,優化了一些。
PHP查詢演算法之二分查詢 折半查詢
折半查詢意為從把陣列從中間分成兩半,找到乙個中間值,然後進行判斷,首先這個陣列一定是從大到小或者從小到大排好序的。下面的 裡陣列是從小到大排序的。遞迴形式的 定義乙個從小到大排好序的陣列 arr 12 34 43 56 77 86 88 90 99 101 要查詢的數字 num 88 count c...
二分查詢 折半查詢 演算法
二分查詢也稱折半查詢 binary search 它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列。首先,假設表中元素是按公升序排列,將表中間位置記錄的 關鍵字與查詢關鍵字比較,如果兩者相等,則查詢成功 否則利用中間位置 記錄將表分成前 後兩個子...
演算法 二分查詢(折半查詢)
二分查詢也稱折半查詢 binary search 它是一種效率較高的查詢方法。使用二分查詢的條件 1.必須採用順序儲存結構。2.必須按關鍵字大小有序排列。通俗一點的說 如果資料是乙個陣列,那麼這個陣列必須是有序的 時間複雜度 o log2n 如圖所示 下面我們來看c語言 include非遞迴實現 v...