你寫的二分法可能有個bug

 

在公衆號裏寫了有 80 多篇原創文章了,大家大多都是利用碎片時間來閱讀公衆號文章,所以我後面的文章也儘量使用更通俗、更簡短的文字。

 

今天要聊的是二分查找法,也被稱作對半查找法,是一種非常高效的查找搜索算法。使用二分查找算法有幾個前提,一個就是你的數據得是有序的,如果不是有序,那就需要先排序

 

其實任何一種算法,都是基於某種數據結構的,二分法適用於保存在數組中的數據,像使用鏈表數據結構保存的數據都不適合使用二分法。

 

這是使用二分法的兩個比較大的前提,你先知道就好了,下面再做解釋。

 

在二分法發明之前,如果要查找某個數是否在數組中,就只能是把數組遍歷一遍,然後一個一個的依次比較了,在數據量不大的情況下這麼做其實也沒啥問題,但是數據量達到一定的級別,或者在一些比較極端的情況下,比如數組中不存在這個數,又或者這個數存在於數組中最後一個元素,這意味着要把數組中所有的元素都遍歷並且比較一遍。

 

我嘗試了好多次用文字來解釋二分法的過程,也參考了網上其他的文章,始終都覺得不容易被理解,所以我準備用一張圖來描述二分法的全過程,你應該看一眼就能明白。

 

 

首先提供一個有序數組,low、mid、high 分別表示數組的起始位置、中間位置、末尾位置,注意這三個位置均爲數組下標。數組一共有 11 個數字,所以剛開始時,low、mid、high 的值分別爲 0、10、5,對應的元素值分別爲 5、19、37。這裏我們要查找的數字爲 21,首先與數組中間元素 56 比較,21 比 56 要小,因爲數組是有序的,那麼中間元素 56 後面的元素就都不需要再看了,所以接下來把數組縮小一半,只留下 5-21 這個區間的數,然後再重複前面的步驟,不斷把數組縮小,直到找到元素,或者數組縮至爲空。

 

下面我再結合一段用 python 實現的二分算法代碼,你可以對照着看。

 

def binarySearch(data_list, val):    
    low = 0                         # 最小數下標    
    high = len(data_list) - 1       # 最大數下標    

    while low <= high:        
        # mid = (low + high) / 2    # 這種寫法會有溢出問題
        mid = low + (high-low) / 2  # 正確寫法    
        if data_list[mid] == val:   # 如果中間數下標等於val, 返回            
            return mid        
        elif data_list[mid] > val:  # 如果val在中間數左邊, 移動high下標            
            high = mid - 1          # 因爲mid下標已經比較過了,所以減1
        else:                       # 如果val在中間數右邊, 移動low下標            
            low = mid + 1           # 同樣因爲mid下標已經比較過了,所以加1
    return False                    # val不存在, 返回None


ret = binarySearch(list(range(20, 1000)), 76)
print(ret)

 

二分法的代碼看起來很簡單,但其實包含幾個小細節,稍不注意就會掉坑裏。

 

1、循環終止條件,是 low <= high,不能寫成 low < high,不然查找數組的邊界值(數組的第一個元素或最後一個元素)可能會查找失敗,你自己可以去試一下。

 

2、mid = (low + high)/2,如果 low 和 high 都很大的情況下,可能會導致溢出問題,所以一般寫成 mid = low + (high-low)/2。

 

3、在每次對半縮小數組後,low 和 high 移動的問題,可以看到代碼裏都分別有加一減一的操作,如果是直接寫成 low = mid 和 high = mid 的話可能會造成死循環,我覺得死循環在這裏不太好理解,你可以認爲 mid 已經在上個循環中已經比較過了,所以數組折半後就不需要再比較 mid 這個元素了。

 

當然這就是最簡單的二分法,數組中沒有重複的元素,如果存在重複的元素那情況又不太一樣了,後面的文章再細說。二分法雖然簡單,但我還是強烈建議你親自動手去寫一寫。

 

對了,前面有說過,二分法爲啥不適合處理保存在鏈表中的數據,因爲鏈表不能像數組一樣通過下標快速訪問元素,只能從頭結點開始順序遍歷,這樣效率並不是最高的。

 

好了,希望文章對你有一點幫助,點個贊,感謝你的支持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章