演算法入門,其實可以像讀小說一樣有趣
本文來源 | 《演算法圖解:像小說一樣有趣的演算法入門書》
作者 | Aditya Bhargava
責編 | 林瑟
我一個非程式設計師,買了這本《演算法圖解》的書在看,剛拆快遞後翻了一會,被我老闆給看到了,被她強行借走去翻了,說很有意思,翻了幾天才還我。。。如果你是下面中任何一種型別的同學,請繼續往下看:
業餘程式設計師
程式設計培訓班學員
需要重溫演算法的計算機專業畢業生
對程式設計感興趣的物理或數學等專業畢業生
演算法是一組完成任務的指令。任何程式碼片段都可視為演算法,但這裡我們只介紹比較有趣的部分,比如,二分查詢。
假設要在電話簿中找一個名字以 K 打頭的人,現在誰還用電話簿!可以從頭開始翻頁,直到進入以 K 打頭的部分。但你很可能不這樣做,而是從中間開始,因為你知道以 K 打頭的名字在電話簿中間。
現在假設你登入 Facebook。當你這樣做時,Facebook 必須核實你是否有其網站的賬戶,因此必須在其資料庫中查詢你的使用者名稱。如果你的使用者名稱為 karlmageddon,Facebook 可從以 A 打頭的部分開始查詢,但更合乎邏輯的做法是從中間開始查詢。
這是一個查詢問題,在前述所有情況下,都可使用同一種演算法來解決問題,這種演算法就是二分查詢。
二分查詢是一種演算法,其輸入是一個有序的元素列表(必須有序的原因稍後解釋)。如果要查詢的元素包含在列表中,二分查詢返回其位置;否則返回null。
下圖是一個例子。
下面的示例說明了二分查詢的工作原理。我隨便想一個1~100的數字。
你的目標是以最少的次數猜到這個數字。你每次猜測後,我會說小了、大了或對了。
假設你從1開始依次往上猜,猜測過程會是這樣。
這是簡單查詢,更準確的說法是傻找。每次猜測都只能排除一個數字。如果我想的數字是 99,你得猜 99 次才能猜到!
01
更佳的查詢方式
下面是一種更佳的猜法。從 50 開始。
小了,但排除了一半的數字!至此,你知道 1~50 都小了。接下來,你猜75。
大了,那餘下的數字又排除了一半!使用二分查詢時,你猜測的是中間的數字,從而每次都將餘下的數字排除一半。接下來,你猜 63(50 和 75 中間的數字)。
這就是二分查詢,你學習了第一種演算法!每次猜測排除的數字個數如下。
不管我心裡想的是哪個數字,你在 7 次之內都能猜到,因為每次猜測都將排除很多數字!
假設你要在字典中查詢一個單詞,而該字典包含 240000 個單詞,你認為每種查詢最多需要多少步?
如果要查詢的單詞位於字典末尾,使用簡單查詢將需要 240000 步。使用二分查詢時,每次排除一半單詞,直到最後只剩下一個單詞。
因此,使用二分查詢只需 18 步——少多了!一般而言,對於包含 n 個元素的列表,用二分查詢最多需要 log2n 步,而簡單查詢最多需要 n 步。
02
對數
你可能不記得什麼是對數了,但很可能記得什麼是冪。log10100相當於問“將多少個10相乘的結果為100”。答案是兩個:10 × 10 = 100。因此,log10100 = 2。對數運算是冪運算的逆運算。
對數是冪運算的逆運算
本文使用大O表示法(稍後介紹)討論執行時間時,log 指的都是 log2。使用簡單查詢法查詢元素時,在最糟情況下需要檢視每個元素。
而使用二分查詢時,最多需要檢查 log n個元素。如果列表包含 8 個元素,你最多需要檢查 3 個元素,因為 log 8 = 3(23 = 8)。如果列表包含1024個元素,你最多需要檢查10個元素,因為 log 1024 = 10(210 =1024)。
下面來看看如何編寫執行二分查詢的 Python 程式碼。你只需知道,可將一系列元素儲存在一系列相鄰的桶(bucket),即陣列中。這些桶從0開始編號:第一個桶的位置為#0,第二個桶為#1,第三個桶為#2,以此類推。
low = 0high = len(list) - 1
你每次都檢查中間的元素。
mid = (low + high) / 2 ←---如果(low + high)不是偶數,Python自動將mid向下取整。guess = list[mid]
如果猜的數字小了,就相應地修改low
。
if guess < item:
low = mid + 1
如果猜的數字大了,就修改high
。完整的程式碼如下。
def binary_search(list, item):
low = 0 (以下2行)low和high用於跟蹤要在其中查詢的列表部分
high = len(list)—1
while low <= high: ←-------------只要範圍沒有縮小到只包含一個元素,
mid = (low + high) / 2 ←-------------就檢查中間的元素
guess = list[mid] if guess == item: ←-------------找到了元素 return mid if guess > item: ←-------------猜的數字大了
high = mid - 1
else: ←---------------------------猜的數字小了
low = mid + 1
return None ←--------------------沒有指定的元素
my_list = [1, 3, 5, 7, 9] ←------------來測試一下!print binary_search(my_list, 3) # => 1 ←--------------------別忘了索引從0開始,第二個位置的索引為1print binary_search(my_list, -1) # => None ←--------------------在Python中,None表示空,它意味著沒有找到指定的元素
03
電腦科學領域著名的旅行商問題
下面就是一個執行時間極長的演算法。這個演算法要解決的是旅行商問題,其計算時間增加得非常快,而有些非常聰明的人都認為沒有改進空間。
有一位旅行商,他需要前往5個城市。
這位旅行商(姑且稱之為 Opus 吧)要前往這5個城市,同時要確保旅程最短,為此,可考慮前往這些城市的各種可能順序。
若按旅程最短的路線來選,5 個城市有 120 種不同的排列方式。因此,解決這個問題需要執行 120 次操作。涉及 6 個城市時,需要執行 720 次操作,依次遞增!
推而廣之,涉及 n 個城市時,需要執行 n!(n 的階乘)次操作才能計算出結果。因此執行時間為 O(n!),即階乘時間。
這種演算法很糟糕!這是電腦科學領域待解的問題之一。對於這個問題,目前還沒有找到更快的演算法,有些很聰明的人認為這個問題根本就沒有更巧妙的演算法。
面對這個問題,我們能做的只是去找出近似答案,高水平的讀者可以在《演算法圖解:像小說一樣有趣的演算法入門書》中研究一下二叉樹!!
掃描下方二維碼閱讀全書
▼
點選閱讀原文,學習演算法也可以很有趣!!
點個在看
學演算法不禿頭
↓↓
相關文章
- 《演算法圖解》讀書筆記—像小說一樣有趣的演算法入門書演算法圖解筆記
- 深度學習入門實戰(一):像Prisma一樣演算法生成梵高風格畫像深度學習演算法
- Redis 資料結構之字串的那些騷操作 -- 像讀小說一樣讀原始碼Redis資料結構字串原始碼
- SnippetsLab - 像納博科夫寫小說一樣寫程式碼
- 讀《像javascript一樣思考》筆記JavaScript筆記
- 讀 Linux 像讀小說「GitHub 熱點速覽 v.22.03」LinuxGithub
- 一個有趣的小例子,帶你入門協程模組-asyncio
- 居然可以像玩遊戲一樣學Git遊戲Git
- [入門向]在Golang中像Python一樣快速使用HTTP請求GolangPythonHTTP
- 用Flutter實現一個小說閱讀AppFlutterAPP
- 「Python實用秘技12」像匯入模組一樣匯入ipynb檔案Python
- 深度有趣 | 14 Dlib快速入門
- 小程式從入門到實戰系列(一)
- Vland:像樂高一樣搭建元宇宙|開發者說元宇宙
- Gitee熱榜第一!讓你可以像操作SQL一樣操作ESGiteeSQL
- 米讀小說
- [譯] 建立一個像科幻小說一樣的虛擬世界:設計一個全球性的虛擬世界虛擬世界
- 小說讀後感
- Easy New File|讓Mac像Windows一樣可以右鍵新建檔案MacWindows
- [提問交流]onethink Admin 可以像Home 一樣做切換 Theme嗎
- 用 Golang 跑「佇列任務」,也可以像 Laravel 一樣簡單Golang佇列Laravel
- Elasticsearch入門及掌握其JavaAPIElasticsearchJavaAPI
- 入門微信小程式 (一)微信小程式
- 一小時入門ReactReact
- 一篇有趣的負載均衡演算法實現負載演算法
- 不一樣的Flink入門教程
- Linux系統中有趣的命令(可以玩小遊戲)Linux遊戲
- 歸納+記憶:讓機器像人一樣從小樣本中學習
- 深度學習,其實和撩妹的套路一樣!深度學習
- 說下Python入門Python
- 假如生活能像vim一樣
- 小學生也能讀懂的Docker入門教程Docker
- 【小入門】react極簡入門React
- 微信小程式入門與實踐微信小程式
- Laravel 實用小技巧 —— Artisan 入門(下)Laravel
- Laravel 實用小技巧 —— Artisan 入門(上)Laravel
- React Ref 其實是這樣的React
- 爬蟲新手入門實戰專案(爬取筆趣閣小說並下載)爬蟲