1. 程式人生 > 其它 >基礎演算法之查詢

基礎演算法之查詢

來自圖解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
努力拼搏吧,不要害怕,不要去規劃,不要迷茫。但你一定要在路上一直的走下去,儘管可能停滯不前,但也要走。