資料結構與演算法之兩種查詢方法
本節的內容:
-
什麼是列表查詢;
-
順序查詢(線性查詢);
-
二分查詢;
-
順序查詢與二分查詢比較;
-
執行時間;
-
增速問題
一:什麼是查詢
查詢:在一些資料元素中,通過一定的方法找出與給定的關鍵詞相同的資料元素的過程。
二:順序查詢(線性查詢):從列表中查詢指定的元素
定義:從列表的第一個元素開始,順序進行搜尋,直到找到元素或搜尋到列表最後一個元素為止。
-
輸入:列表、帶查詢的元素
-
輸出:元素下標(未找到元素是一般返回None/-1)
-
內建列表查詢函式:index()
1 #線性查詢的程式碼實現 2 #enumerate() 函式用於將一個可遍歷的資料物件(如列表、元組或字串)組合為一個索引序列,同時列出資料和資料下標,一般用在 for 迴圈當中。 3 #教程:https://www.runoob.com/python3/python3-func-enumerate.html 4 def linear_search(li,var): 5 for index,v enumerate(li): 6 if v == var: 7 return index 8 else: 9 return None 10 複雜度:範圍是列表(n),一個for迴圈====》O(n) 從頭到尾遍歷每個元素
三:二分查詢定義
又叫折半查詢,從有序列表(必須為有序)的初始候選區list[o:n]開始,通過對待查詢的值與候選區中間值的比較,可以使候選區減少一半。(僅當列表為有序的時候,二分查詢才管用)
舉例:從下面列表中查詢3元素:
首先我們需要對候選區做一個瞭解,這樣有助於我們更好的理解,
在上面的列表中我們使1所在的位置為left,9所在的位置為right,這樣從left-right就是候選區,
候選區中間值(mid) =(left-right)// 2;如果我們需要查詢的值(val)大於候選區中間值(mid),則左邊的值為:left = mid+1 ,right不變,候選區為:【(mid+1),right】;相反:查詢的值(val)小於候選區中間值(mid),則left不變,右邊值為:right = mid - 1,候選區為【left, ( mid -1)】
然後依次進行取值,其中left、mid、right都是指的值的下標;如果最後left>right,則表示該範圍沒有所需要的值。
程式碼如下:
1 def Binary_search(li,val): #li傳入的列表,val所需要的值 2 '''定義值''' 3 left = 0 4 right = len(li) - 1 5 while left <= right: #候選區有值 6 mid = (right+left) // 2 #候選區中間值 7 if li[mid] == val: 8 return mid 9 elif li[mid] > val: #帶查詢的值在中間值(mid)的左側 10 right = mid -1 11 else: #li[mid] < val 帶查詢的值在中間值(mid)的右側 12 left = mid + 1 13 else: 14 return None
四:順序查詢與二分查詢比較
我們在使用大O表示法討論執行時間時,log指的都是log2。使用簡單查詢法查 找元素時,在最糟情況下需要檢視每個元素。
因此,如果列表包含8個數字,你最多需要檢查8 個數字。而使用二分查詢時,最多需要檢查log n個元素。如果列表包含8個元素,你最多需要 檢查3個元素,因為log 8 = 3(2^3 = 8)。如果列表包含1024個元素,你最多需要檢查10個元素, 因為log 1024 = 10(2^10 =1024)。
五:兩者執行時間
選擇演算法的時候我們本能的選擇效率最高的,以最大限度的減少執行時間或者佔用空間。
如果列表包含100個數字,順序查詢最多需要猜100次,40億個數字,則最多需要才40億次;順序查詢最多需要猜測的次數與列表長度相同==》執行時間線性時間。
二分查詢的話最多猜7次,40億最多猜32(log2^32)次===>執行時間表示為對數時間。
六:增速問題 (演算法的執行時間以不同的速度增加 )
隨著元素數量的增加,二分查詢需要的額外時間並不多, 而順序查詢需要的額外時間卻很多。因此,隨著列表的增長,二分查詢的速度比順序查詢快得多,但如果是無序列表,使用二分查詢的話需要進行排序,兩者各有優缺點,