基礎演算法之查詢
來自圖解LeetCode初級演算法的筆記(分塊查詢沒有研究)
為什麼要查詢
查詢是搜尋演算法,可用在判斷一個數是否在該數列種,或者找出一個無序數列中該數列的位置
順序查詢
就是將數列從頭到尾的查詢一遍
for i in rang(array):
if array[i]==key:
return i
return -1
二分法查詢
直接找數列中間的那個數字與被查詢數(key)相比。如果這個數比key小,在就在這個有序數列的前面,否則就是這個然,要不然就在這個數的後面。相應的知道了範圍,我們就可以在那個範圍中去查詢。
這裡的關鍵在於如何確定,那一部分索引的中間元素,這裡先引入索引0,和最後一個索引,先求出中間的索引,然後判斷是在前的話,就把中間索引複製給right,然後繼續求中間索引,這樣不有可能會求不到麼。不會,因為是有序的。
left = 0 right = iLen -1 # 重新迴圈遍歷,left,rignt重新賦值;這樣來確定一半索引處的位置麼;一個部分中的中間元素 while right - left > 1: mid = (left + right) // 2 # 一半索引處 if key < iList[mid]: right = mid # 一半索引值給了right elif key > iList[mid]: left = mid # 一半索引值給了left else: return mid # 跳出迴圈體所在的方法,相當於跳出迴圈體。
斐波那契查詢
又稱黃金分隔數列,指的是該數列中相鄰兩個數的桌布越趨向於黃金比例值。相較於二分查詢來說,它的分隔點是0.618,假如一個數列中有1000個數,二分查詢法查詢的位置在索引500這,而斐波那契查詢則在618這。
斐波那契查詢的索引是按照斐波那契數的排列,比如數列長10,則找一個比他大的斐波那契數13,找13之前的斐波那契數8,找這個索引。然後不斷迴圈,直至找到那個書。這裡就需要用到斐波那契數列的構建,也就是遞迴了。
斐波那契數的列表相加生成
def fibonacci(n): '''return the last element of the fibonacci sequence''' fList = [1, 1] while n > 1 : fList.append(fList[-1] + fList[-2]) n -= 1 print(fList) return fList[-1]
接著是fibonacci查詢關鍵程式碼
k = 1
while fibonacci(k) -1 < iLen - 1: #fibonacci數列中的最後一個元素要比iList的長度稍微大一點
k += 1
while right - left > 1:
mid = left + fibonacci(k - 1) # fibonacci數列中的最後一個元素前面的那個數
if key < iList[mid] :
right = mid - 1 # 在左邊,則中間索引減少一
k -= 1 # 斐波那契數是前面一個元素
elif key == iList[mid]:
return mid
else:
left = mid + 1 # 在右邊的話,中間索引加1,並且賦值給左邊
k -= 2 # k-2沒搞懂,為啥減少2呢
插值查詢
fibonacci查詢和二分查詢的區別在於查詢數列中選取比較點(參照點)。而插值查詢則給出了一個大多數情況下的理論上最科學的比較點
mid = left +(key-iList[left])*(right-left)//(iList[right]-iList[left]) # 那為什麼這個點是查詢的最優點呢
插值查詢關鍵程式碼
while right - left > 1:
mid = left + (key - iList[left]) * (right - left) // (iList[right] - iList[left])
if mid == left:
mid += 1 #當iList[right]和iList[left]相差太大時,有可能導致mid一直都等於left,從而陷入死迴圈
if key < iList[mid]:
right = mid
elif key > iList[mid]:
left = mid
else:
return mid
if key == iList[left]:
return left
elif key == iList[right]:
return right
else:
return -1
分塊查詢
分塊查詢與以上的查詢方式不同,順序查詢的數列可以是無序的,二分查詢和斐波那契查詢數列必須是有序的,分塊查詢介於兩者之間,需要塊有序,元素可以無序。插值查詢也是有序查詢
原理:
按照一定的取值範圍將數列分成數塊,塊內的元素可以是無序,單塊必須有序
塊有序:處於後面位置的塊中的最小元素都要比前面位置塊中的最大元素大
第一次查詢是將被查詢數key與塊的分界數相比較,確定key屬於哪個塊
第二次查詢
塊內的查詢就是順序查詢
分塊操作(沒研究)
iList = randomList(20)
indexList = [[250, 0], [500, 0], [750, 0], [1000, 0]]
def divideBlock():
global iList, indexList
sortList = []
for key in indexList: # 分塊操作
subList = [i for i in iList if i < key[0]] #列表推導, 小於key[0]的單獨分塊
key[1] = len(subList)
sortList += subList # 加入到新建的列表中
iList = list(set(iList) - set(subList)) #過濾掉已經加入到subList中的元素
iList = sortList
print()
return indexList
在塊中進行查詢
def blockSearch(iList, key, indexList):
print("iList = %s" %str(iList))
print("indexList = %s" %str(indexList))
print("Find The number : %d" %key)
left = 0 #搜尋數列的起始點索引
right = 0 #搜尋數列的終點索引
for indexInfo in indexList:
left += right
right += indexInfo[1]
if key < indexInfo[0]:
break
for i in range(left, right):
if key == iList[i]:
return i
return -1
努力拼搏吧,不要害怕,不要去規劃,不要迷茫。但你一定要在路上一直的走下去,儘管可能停滯不前,但也要走。