二分查找會更快嗎?Python中的二分查找與線性查找性能測試

2021-01-11 deephub

當您要檢查某個元素是否在列表中時,有很多方法可以解決相同的問題。可以通過線性查找和二分查找來完成,但是要猜測哪個更快。

為什麼?

如果你最近參加過面試,你就會知道二分查找是面試官的最愛。

您為什麼要花時間學習二分查找? C ++編程朋友可能已經告訴過您。 Python很慢。 您想確保自己的程序不會比所需的速度慢。

學習Python時,您將學習進行線性查找以檢查元素是否在列表中。 當您學習編碼時很好,但是如果列表中有60.000.000個元素會發生什麼呢?

如果在包含11個元素的列表中進行線性查找,則必須遍歷所有11個元素。 如果您使用二分查找,最終可能要進行2次迭代,具體取決於您要查找的內容。 請參見下面的圖形。

顯而易見,哪種方法更快。

開始學習Python時,您很可能已經使用了一百次列表。 檢查列表中是否有一個值是一項正常的任務,您之前已經看到過:

my_list = [1,2,3,3,5,11,12]if 11 in my_list:return Truereturn False

或者

my_list = [1,2,3,3,5,11,12]for each in list:if each==11: return Truereturn False

讓我們開始看看如何實現二分查找。

怎麼做?

讓我們看看二分查找是如何工作的。

首先,我們需要確保列表是有序的。您可以使用.sort()或sorts()對列表進行排序,我使用.sort()在適當的地方修改列表。如果出於某種原因需要一個新列表,或者不想篡改原始列表,可以使用sorted()

這是我們的測試內容:

bin_list = [1,2,3,5,6,9,11,12,15,20,22]search_value_a = 15

我們要尋找15的值。

我們的起點。具有最小值和最大值的列表:

當我們做二分查找時,我們從尋找列表中的中間元素開始:

中間索引為5,值為9。首先我們要知道9是不是我們要找的數字。記住,我們要找的是15。如果不是,我們檢查它是更高還是更低。在這個例子中,9比15小,所以我們需要設置一個新的最小值點。我們知道我們不再需要擔心列表的下半部分。新的最小點將被設置為列表上部的第一個可能的項。

使用新的中點,我們檢查這是否是我們要尋找的數字。在這種情況下,正好是15,這樣這次查找就完成了。

如果我們要找的是2,而第一個中間值是9,你覺得這個算法會怎麼做?你是對的。取而代之的是max指數。

代碼

通俗的流程解釋如下:

用列表和目標作為參數創建函數。確保列表是有序的。

獲取列表長度- 1為最大,0為開始。循環將:

獲得新的中間值檢查中間值是否高於或低於目標值。檢查結束後,將最小值或最大值移到中間。如果middle == target,返回True如果我們到達列表的末尾,則目標不在列表中下面看看代碼實現:

mport randomdef binary_search(input_list , target_value):''' Function executing binary search to find if element is in a list. parameters: - list - target return value: True/False (bool) ''' input_list.sort() min_index = 0 max_index = len(input_list) -1 while max_index >= min_index: mid_index =(max_index+min_index)//2 if input_list[mid_index] == target_value: return True elif input_list[mid_index] < target_value: min_index = mid_index+1 else: max_index = mid_index-1 return Falsedef main(): #bin_list = list(range(6,501)) bin_list = [1,2,3,5,6,9,11,12,15,20,22] search_value_a = 15 search_value_b = 7 assert binary_search(bin_list,search_value_a) == True assert binary_search(bin_list,search_value_b) == Falseif __name__ == '__main__': main()

我們已經創建了一個具有兩個參數的函數。列表和目標值。目標值就是我們要找的數字。這個列表就是我們要遍歷的,用來尋找數字的列表。

def binary_search(input_list , target_value):

如果我們找到了目標值,我們將返回True。如果不是,我們將返回False。

我們要做的第一件事是對列表進行排序,並定義列表的最小索引和最大索引。

input_list.sort()min_index = 0max_index = len(input_list) -1

我們使用len(list)-1的原因是Python從0開始索引。測試列表的長度是11,但是最後一個索引是[10]。

現在,讓我們進入主要的功能,循環:

while max_index >= min_index:mid_index =(max_index+min_index)//2 if input_list[mid_index] == target_value: return True elif input_list[mid_index] < target_value: min_index = mid_index+1 else: max_index = mid_index-1

只要最大值不大於最小值,我們就繼續。如果循環停止了,那就意味著我們已經摺疊了列表,使得最大值小於最小值。此時,沒有必要查找這個值,因為沒有更多的列表了。

mid被設置為最大值和最小值的平均值。請注意我們是如何使用整數除法的,例如7//2將是3而不是3.5。這樣,我們總是為索引得到一個乾淨的整數。

如果帶有中間索引的列表項的值等於我們的目標值,我們就成功了!返回True,然後退出。

如果這個值小於目標值,我們知道我們必須把最小索引推到那個點。因此新的最小值是中間+1

如果該值不等於或小於目標值,則會較大。這意味著我們可以刪除列表的頂部並將最大索引下壓。max被設置為中間-1

如果您覺得難以理解,可以在代碼中添加print(),以獲得索引跳躍的可視化表示。

在while循環的midindex =(maxindex+min_index)//2之後添加這個:

print (f'min: {min_index} , mid: {mid_index} , max: {max_index}')

但是它更快嗎?

該函數的時間複雜度為O(n),其中n為鍊表的長度。為了檢驗哪種查找更快,我們可以計算二分查找相對於線性查找的時間。

首先,我們需要寫出一個線性查找函數:

def linear_search(input_list, target_value):for each in input_list: if each==target_value: return True return False

下面我們可以進行對比了:

def binary_performance():run_setup = '''from __main__ import binary_search''' run_code = '''bin_list = list(range(6,501))binary_search(bin_list,15)''' performance = timeit.repeat(setup = run_setup, stmt = run_code, repeat = 3, number = 10_000) print(f'binary search performance = {round(min(performance),2)}')def linear_performance(): run_setup = '''from __main__ import linear_search''' run_code = '''lin_list = list(range(6,501))linear_search(lin_list,15)''' performance = timeit.repeat(setup = run_setup, stmt = run_code, repeat = 3, number = 10_000) print(f'linear search performance = {round(min(performance),2)}')binary_performance()linear_performance()

陷阱

如果您運行上面的代碼(與原始代碼合併),您將看到線性查找更快了。這是什麼魔法?

有幾個問題給二分查找帶來了困難。

排序

列表的長度

低於目標的值

以上所有因素,讓線性領先。現在讓我們繼續排序,先改變列表長度:

bin_list = list(range(1,10000))lin_list = list(range(1,10000))

線性查找仍然佔上風。讓我們對函數進行排序,並在將列表傳遞給函數之前對其進行排序。(這對線性查找是不公平的,因為線性並不依賴於排序列表)。我們所要做的就是在列表排序時注釋掉它。

二者速度比較接近了。

如果我們將目標值移動到7,500呢?現在我們的偏差很明顯,因為我們真的想讓二分更快。

這次的差異是極端的。下面的最後一個例子將使情況更加公平。

讓我們以隨機長度和隨機目標創建一個隨機列表。然後我們將為這兩個函數運行100,000次。

test_list = list(range(1,random.randint(2,50000)))test_number = random.randint(2,50000)binary_search(test_list,test_number)

現在讓我們運行10萬次!,我相信這些結果。上圖是排序後結果,下圖需要進行排序

總結

二分比線性快嗎?是的,但要看情況而定。

如果有人告訴你二分查找更快,那是因為它通常是更快的。

和往常一樣,你必須看一看設置,不要每次都去找一個單一的解決方案,因為它「是最好的」。

我們從實驗中看到,這取決於你在做什麼。如果您有一個簡短的列表,或者如果您在列表的下半部分尋找元素,那麼執行線性查找可能會更好。

這也是編程之美。你不應該在不知道為什麼的情況下使用一種方法來做某事。如果你還不知道二分查找,現在你有了另一個工具來做查找。只要你覺得它有用,就使用它。

我希望我們能在一件事上達成一致。二分查找是相當酷的!

作者:Martin Andersson Aaberge

deephub翻譯組

相關焦點

  • 二分查找大集合(媽媽再也不用擔心我的二分查找了)
    來自:韓子遲 - 博客園作者:韓子遲【github:https://github.com/hanzichi 求關注】連結:http://www.cnblogs.com/zichi/p/5118032.html已獲轉載授權什麼是二分查找就不多說了
  • 入門計算機必會的算法——二分查找法
    不希望能學得有多麼高深,只希望在一些最基本的算法上有編碼的思路,或者在一些生產環境中會應用一些算法來解決實際問題。就比如今天要介紹的第一個查找算法——二分查找法。假設要在電話薄中找一個名字為K大頭的人,很習慣的辦法就是從頭開始翻頁,直到進入以K打頭的部分。但是這種方法的缺陷就是要逐一查找,時間較長。於是我們可以有另外一個思路就是每次從中間開始查找,而以K打頭的名字就在電話簿中間。
  • 二分查找法(折半查找法)
    /*二分查找法說明:如果搜尋的數列已經有排序,應該儘量利用它們已排序的特性,以減少搜尋比對的次數 ,這是搜尋的基本原
  • 聊聊一看就會一寫就跪的二分查找
    不僅如此,本特利自己1986年出版的《編程珠璣》一書中的二分查找算法存在整數溢出的問題,二十多年來無人發現。Java語言的庫所實現的二分查找算法中同樣的溢出問題存在了九年多才被修復。所以我寫下了這篇文章,希望能夠徹徹底底地講明白我心目中的「二分查找」到底是什麼。在弄懂它的本質以後不管遇到什麼類型的二分查找問題,都能夠準確無誤地寫出正確的代碼。
  • 使用Python和C語言實現二分法查找(折半查找)
    二分查找 叫折半查找,它對要查找的序列有兩個要求,一是該序列必須是有序的,二是該序列必須是順序存儲的。二分法查找算法的原理如下:1、 如果待查對象為空返回-1,表示查找不到目標元素2、 如果待查序列不為空,則將中間元素與要查找的目標元素進行匹配看是否相等,如果相等表示 查找成功,返回該中間元素的索引如果不相等再比較這兩個元素的大小
  • JAVA編程——二分法查找
    一、二分法檢索過程二分法檢索(binary search)又稱折半檢索,二分法檢索的基本思想是設數組中的元素從小到大有序地存放在數組(array)中(註:二分法查找的關鍵,首先數組元素必須從小到大有序排列),(1)首先將給定值 key 與數組中間位置上元素的關鍵碼(key)比較,如果相等,則檢索成功
  • 一篇文章讓你了解二分搜索樹的數據結構的實現過程(Java 實現)
    舉個例子:比如對於查找一個數據,在線性結構中如果不知道具體位置的話需要在一堆數據裡一個一個地去尋找;而對於樹結構,因為樹結構分支的形式,各個數據可以存在不同的分支中,在查找時就可以依據這些分支快速地找到想要的數據。
  • 「查找我的iphone」,原來這麼強大!
    在我們購買的智慧型手機裡,蘋果有"查找我的Iphone",谷歌有"查找我的設備"。該功能可能很多人會關閉,覺得只是一個定位的作用,沒有開啟的必要。其實這個功能在我們日常生活是很有用的,"查找我的iPhone"不是單純用來定位iPhone的,旨在用於在iPhone、iPad、Mac、Apple Watch或AirPods不小心遺失後找回產品的。
  • 論文文獻去哪裡查找?怎麼查找?
    論文文獻去哪裡查找?怎麼查找?如何高效地從閱讀的文獻中獲取需要的知識和內容?作為論文服務平臺小編為您總結了一下幾種查找文獻的方法和渠道,有疑問的朋友可以做下參考:論文文獻怎麼查找如果您還是學生如果您是職場人員,可以通過網絡查找,使用次數比較多的就是知網、萬方和維普。在知網、萬方和維普官網的檢索頁面有相應的檢索功能。如圖:可以充分利用關鍵詞、時間範圍等檢索條件進行精準檢索。如果沒有這些檢索平臺的帳號,不能下載到PDF格式的文件,只能是望洋興嘆。
  • 科技:如何使用「查找我的iPhone」查找丟失的耳機
    導語:很高興大家來到這,今天小編和大家來講講對於蘋果AirPods,如何使用「查找我的iPhone」查找丟失的耳機,快來看看吧!在AirPods推出後不久,Apple將它們添加到了Find My iPhone應用程式中,如果您發現自己正在尋找丟失的AirPod或者兩個,那麼這正是您需要去的地方。在我們介紹如何找到丟失的Pod之前,您需要注意以下幾點:當充電盒打開或AirPods在盒子外面時,「查找我的iPhone」僅與您的AirPods交互。
  • 丟了手機"查找我的iPhone"能找回來嗎?
    品牌:蘋果 手機1"查找我的iPhone"能找回手機嗎?    近日,關於蘋果手機的一款應用在網上以及各大論壇裡被炒得沸沸揚揚,這款應用的名字叫「查找我的iPhone」。
  • 《紅警手遊》仇人坐標查找方法 怎麼查找仇人位置
    這款手遊相信吸引了不少朋友來玩,不過PK的時候會遭遇仇人,那麼仇人應該怎麼找呢?那麼小編今天就為大家帶來了仇人坐標查找方法介紹! 紅警OL手遊仇人坐標查找方法 坐標,(0,... 紅警手遊仇人坐標怎麼找?這款手遊相信吸引了不少朋友來玩,不過PK的時候會遭遇仇人,那麼仇人應該怎麼找呢?
  • 查找醫學文獻的方法
    國內外醫學文獻浩如煙海,怎樣從中獲取所需要的醫學文獻,是一門學問。就目前而言,查找醫學文獻的方法主要有兩種,一種是手工查找法,一種是網上電腦查找法。依據醫刊彙編譯的實踐體會來看,兩種方法各有千秋,電腦檢索雖然非常快捷,但常把需要和不需要的文獻一起提供,有時也會遺漏所需要的文獻。
  • OpenCV-Python 直方圖-1:查找、繪製和分析|二十六
    但是考慮一下,如果您不需要分別找到所有像素值的像素數,而是找到像素值間隔中的像素數怎麼辦?例如,您需要找到介於0到15之間的像素數,然後找到16到31之間,...,240到255之間的像素數。只需要16個值即可表示直方圖。這就是在OpenCV教程中有關直方圖的示例中顯示的內容。
  • Java字符串地查找操作
    在一個字符串中查找字符或子串是經常使用的操作。String類提供了兩種查找字符串的方法,分別是indexOf()和lastIndexOf(),這兩種方法都返回待查找字符或子串在字符串的起始索引位置。使用String類的indexOf()方法在szTemp中查找szSearch,若szTemp內容包含szSearch,則查找成功。indexOf()方法返回szSearch在szTemp中的起始索引,然後使用String類的substring方法截取子串。
  • ADSP TigerSHARC中利用查找表快速計算三角函數
    在這種情況下,利用查找表的方法來得到三角函數的值就成為一種可行,並能獲得很高實時性的計算方法。本文給出了一種在TS101中利用查找來實現三角函數計算的方法,並對這種算法的誤差和運算量進行了分析,從結論可以看出,文中提出的通過查找表計算三角函數的方法有效而且運行效率比較高。
  • EXCEL之VBA應用實例-FIND查找和FindNext繼續查找的使用方法
    ) '查找內容為「黃」字,如果加上參數lookat:=xlWhole,就是完全匹配,單元格只有一個「黃」字才算找到,這裡演示的是不指定,默認就是單元格內容「包含」這個字就可以了,注意的事,如果手動在查找替換窗口裡把「單元格匹配」勾打上的話,這裡不進行設置會直接按手動在「查找替換」窗口中設置的值進行查找。
  • 一篇文章搞懂 數據結構中的 線性表存儲方式(順序表 與 鍊表)
    數據結構從邏輯層面上分為線性結構和非線性結構。線性結構:顧名思義,就是數據連成線一樣存儲。非線性結構:分為 樹 和 圖,樹與圖的區別就是:樹是沒有環路的,從大的意義來看,圖是包含樹的,即沒有環路的圖就是樹。線性表線性表是線性結構的基本表現。線性表有兩種存儲方式:順序表鍊表。
  • 振鈴/鎖定/清除 Lumia1520丟失也能查找
    在成功遠程登陸帳號之後,你會看到系統提供的三項功能:分別是振鈴、鎖定以及清除。經過實際測試,Lumia1520在開啟聲音、靜音、震動三種情況下都可以發出報警的聲音,不過此時點擊設備任何按鍵都可以結束聲音,所以這項功能的作用其實並不大,更多的用於尋找在附近丟失手機時會用到。
  • 查找我的iphone在哪裡
    蘋果手機查找我的iPhone在哪裡?近來身邊越來越多的朋友都使用上了蘋果產品,那麼對於長期使用蘋果手機的用戶來說,你知道怎麼打開查找我的iPhone功能呢?不知道的話,就隨便小編一起往下來了解一下吧。查找我的iphone在哪裡:1,點擊蘋果手機的「設置」圖標進入。2,進入設置界面,點擊「隱私」選項,並開啟「定位服務」功能下一步。3,開啟定位服務功能後,返回到設置界面。