写给中学生的算法入门:学代码之前看这篇就够了
導(dǎo)讀:本文內(nèi)容主要源自德語大學中發(fā)起的科普活動,初衷是讓高中生領(lǐng)會算法和計算機科學的奇妙與魅力。閱讀本文不需要任何關(guān)于算法和計算的預(yù)備知識。我們希望不僅學生,而且包括希望了解迷人的算法世界的成年人都能從本書中得到啟發(fā)與樂趣。
作者:Thomas Seidl,?Jost Enderle,?Wolfgang P. Kowalk,?Berthold V?cking
本文摘編自《無處不在的算法》,如需轉(zhuǎn)載請聯(lián)系我們
00 算法的應(yīng)用
最近幾十年來許多技術(shù)創(chuàng)新和成果都依賴于算法思想,這些成果廣泛應(yīng)用于科學、醫(yī)藥、生產(chǎn)、物流、交通、通信、娛樂等領(lǐng)域。高效的算法使得你的個人電腦得以運行新一代的游戲,這些復(fù)雜的游戲在幾年前可能都難以想象。
更重要的是這些算法為一些重大科學突破提供了基礎(chǔ)。例如,人類基因組圖譜解碼得以實現(xiàn)與新算法的發(fā)明是分不開的,這些算法能將計算速度提高幾個數(shù)量級。
算法告訴計算機如何處理信息,如何執(zhí)行任務(wù)。算法組織數(shù)據(jù),使得我們能有效地搜索。如果沒有聰明的算法,我們一定會迷失在互聯(lián)網(wǎng)這個巨大的數(shù)據(jù)叢林中。
同樣,如果沒有天才的編碼和加密算法,我們也不可能在網(wǎng)絡(luò)上安全地通信。天氣預(yù)報與氣候變化分析也依靠高效模擬算法。
工廠生產(chǎn)線和物流系統(tǒng)有大量復(fù)雜的優(yōu)化問題,只有奇巧的算法能幫助我們解決。甚至當你利用GPS尋找附近的餐廳或咖啡館時,也要靠有效的最短路計算才能獲得滿意的結(jié)果。
并非像很多人認為的,只有計算機中才需要算法。在工業(yè)機器人、汽車、飛機以及幾乎所有家用電器中都包含許多微處理器,它們也都依賴算法才能發(fā)揮作用。例如,你的音樂播放器中使用聰明的壓縮算法,否則小小的播放器會因為存儲量不足而無法使用。
現(xiàn)在的汽車和飛機中有成百上千的微處理器,算法能幫助控制引擎,減少能耗,降低污染。它們還能控制制動器和方向盤,提高穩(wěn)定性與安全性。不久的將來,微處理器可能完全替代人,實現(xiàn)汽車的全自動駕駛。目前的飛機已經(jīng)能做到在從起飛到降落的全過程中無須人工干預(yù)。
算法領(lǐng)域最大的進步都來自美好的思想,它指引我們更有效地解決計算問題。我們面對的問題絕不局限于狹義的算術(shù)計算,還有很多表面上不是那么“數(shù)學化”的問題。例如:
如何走出迷宮?
如何分割一張藏寶圖讓不同的人分別保存,但只有重新拼合才可能找到寶藏?
如何規(guī)劃路徑,用最小成本訪問多個地方?
這些問題極具挑戰(zhàn),需要邏輯推理、幾何與組合想象力,還需要創(chuàng)造力才能解決。這些就是設(shè)計算法所需要的主要能力。
01 二分搜索
我新買的Nelly的唱片哪兒去啦?我那專橫的妹妹Linda有整潔癖,肯定是她將唱片又插進唱片架上了。我告訴她新買的唱片別插上去。這下我得在架子上的500張唱片中一張一張地找了,這該找到什么時候啊!
不過,走運的話也可能并不需要查看所有唱片就碰到了。但最壞的情況是Linda又把唱片借給朋友了,那得查完所有唱片才知道不在這里了,然后只好去聽廣播啦。
找找看吧!Aaliyah,AC/DC,Alicia Keys……嗯,Linda好像按字母順序給唱片排過序了。這樣的話我找Nelly的唱片就容易多了。
我先在中間試試。Kelly Family,這太偏左了,必須往右邊找。Rachmaninov,這又太偏右了,再往左一點兒……Lionel Hampton,右了點兒,但不遠了。Nancy Sinatra……Nelly,找到啦!
這倒很快!因為唱片已經(jīng)排了序,我只要來回跳幾次就找到目標了!即使我要的唱片不在架子上,我也能很快發(fā)現(xiàn)。不過如果唱片很多,比如說10 000張,那可能得來回跳上幾百次吧。我很想知道如何計算次數(shù)。圖1-1給出了不同搜索方法的示意。
▲圖1-1 順序搜索與二分搜索圖示
1. 順序搜索
Linda從去年開始學習計算機科學;她應(yīng)該有些書能告訴我答案。我看看,“搜索算法”可能有用。這里說了如何在一個給定集合(這里是唱片)中按照關(guān)鍵字(這里用藝術(shù)家的名字)找一個對象。我剛才的做法應(yīng)該是“順序搜索”,又叫“線性搜索”。
就像我想的一樣,為了找一個關(guān)鍵字,平均得檢查一半的唱片。搜索的步數(shù)和唱片數(shù)成正比,換句話說,唱片數(shù)增加一倍,搜索時間也就增加一倍。
2. 二分搜索
我用的第二種技術(shù)好像有個特別的名字,叫“二分搜索”。給定要找的關(guān)鍵字以及排好次序的對象列表,搜索從中間那個對象開始,和關(guān)鍵字進行比較。如何中間那個對象就是要找的,搜索就結(jié)束了。
否則,按照要找的關(guān)鍵字是小于還是大于當前檢查的對象決定該向左還是該向右繼續(xù)搜索。接下來就是重復(fù)上面的過程。
如果找到了搜尋的對象,或者當前可能搜索的區(qū)間已經(jīng)不能再切分了(也就是說如果表中有要找的對象,當前位置就該是目標應(yīng)該在的位置),搜索就終止。我妹妹的書中有相應(yīng)的程序代碼。
在這段代碼中,A表示一個“數(shù)組”,也就是由帶編號的對象(我們稱其為數(shù)組的元素)構(gòu)成的數(shù)據(jù)列表,編號就像唱片在架子上的位置。例如,數(shù)組中第5個元素寫為A[5]。
如果我們的架子上放了500張唱片,我們要找的關(guān)鍵字是"Nelly",那就得調(diào)用BINARYSEARCH(rack, "Nelly", 1, 500)搜索要找的唱片所在位置。程序執(zhí)行時,開始的left值為251,right值為375,以此類推。
3. 遞歸實現(xiàn)
在Linda的書中還有另外一個二分搜索算法。同樣的功能為什么需要不同算法呢?書上說第二種算法采用“遞歸方法”,那又是什么呢?
我再仔細看看……“遞歸函數(shù)是一種利用自身來定義或者調(diào)用自己的函數(shù)。”求和函數(shù)sum就是個例子。函數(shù)sum的定義如下:
sum (n) = 1 + 2 + … + n
也就是前n個自然數(shù)相加,所以,當n = 4,可得:
sum (4) = 1 + 2 + 3 + 4 = 10
如果我們想計算對于某個n的sum函數(shù)值,而且已經(jīng)知道對于n-1的函數(shù)值,那只要再加上n就可以了:
sum (n) = sum (n-1) + n
這樣的定義式就稱為“遞歸步”。當要計算對于某個n的sum函數(shù)值時,我們還需要一個最小的n對應(yīng)的函數(shù)值,這稱為奠基:
sum (1) = 1
按照遞歸定義,我們現(xiàn)在計算sum函數(shù)值的過程如下:
sum (4) = sum (3) + 4
= (sum (2) + 3) + 4
= ((sum (1) + 2) + 3) + 4
= ((1 + 2) + 3) + 4
= 10
二分搜索的遞歸定義是一樣的:函數(shù)在函數(shù)體中調(diào)用自己,而不是反復(fù)執(zhí)行一組操作(那稱為循環(huán)實現(xiàn))。
和前面一樣,A是要搜索的數(shù)組,key是要找的關(guān)鍵字,left和right分別是搜索區(qū)域的左右邊界。如果我們要在包含500個元素的數(shù)組rack中找Nelly,我們采用類似的函數(shù)調(diào)用BINSEARCHRECURSIVE(rack,"Nelly",1,500)。但這里不再通過程序循環(huán)使得搜索區(qū)域左右邊界逐步靠近,而是直接修改邊界值執(zhí)行遞歸調(diào)用。實際執(zhí)行的遞歸調(diào)用序列如下:
BINSEARCHRECURSIVE (rack, “Nelly”, 1, 500)
BINSEARCHRECURSIVE (rack, “Nelly”, 251, 500)
BINSEARCHRECURSIVE (rack, “Nelly”, 251, 374)
BINSEARCHRECURSIVE (rack, “Nelly”, 313, 374)
BINSEARCHRECURSIVE (rack, “Nelly”, 344, 374)
...
4. 搜索的步數(shù)
至此,我們?nèi)匀徊恢酪业剿璧膶ο缶烤乖搱?zhí)行多少搜索步。如果運氣好,一步就能找到。反之,如果要找的對象不存在,我們必須來回跳動直至對象應(yīng)該處于的位置。
這樣就需要考慮究竟數(shù)組能夠被切為兩半多少次,或者反過來說,當執(zhí)行了一定數(shù)量的比較操作后,究竟多少元素可以被確定是或者不是目標對象。
假設(shè)要找的對象確實在表中,一次比較可以確定2個元素,兩次比較可以確定4個元素,三次比較就能確定8個元素。因此執(zhí)行k次比較操作能夠確定2·2·…·2(k次)= 2k個元素。由此可知10次比較可以確定1024個元素,20次比較能確定的元素超過100萬個,而30次比較能確定的元素多達10億個以上。
如果目標對象不在數(shù)組中,則需要多比較一次。為了能根據(jù)元素個數(shù)確定比較次數(shù),我們需要逆運算,也就是2的乘冪的反函數(shù),即“以2為底的對數(shù)”,記作log2。一般地說:
假設(shè)a = bx,則x = logba
對于以2為底的對數(shù),b = 2:
20 = 1, log2 1 = 0
21 = 2, log2 2 = 1
22 = 4, log2 4 = 2
23 = 8, log2 8 = 3
.
.
. .
.
.
210 = 1 024, log2 1 024 = 10
.
.
. .
.
.
213 = 8 192, log2 8 192 = 13
214 = 16 384, log2 16 384 = 14
.
.
. .
.
.
220 = 1 048 576, log2 1 048 576 = 20
因此,若k次比較操作能確定N(= 2k)個元素,那么對于含N個元素的數(shù)組,二分搜索需要執(zhí)行l(wèi)og2 N = k次比較操作。如果我們的架子上放了10 000張唱片,我們需要比較log2 10 000≈13.29次。因為不可能比較“半次”,需要的次數(shù)為14。
要想進一步減少二分搜索需要的步數(shù),可以在搜索過程中不是簡單地選擇中間元素進行比較,而是嘗試在搜索區(qū)域內(nèi)更準確地“猜測”可能的位置。
假設(shè)在已排序的唱片中搜索的對象名按字母順序更靠近區(qū)域開始處,例如找Eminem,顯然選擇前部的某個位置進行比較更好些。反之,要找“Roy Black”,從靠后的地方開始更合理。
若要更好地改進,就得考慮每個字母可能出現(xiàn)的頻率,例如首字母是D或S的藝術(shù)家通常比首字母是X或Y的更常見。
5. 猜數(shù)游戲
今晚我要考考Linda,讓她猜1到1000之間的某個數(shù)。只要上課沒睡覺,她就應(yīng)該能最多通過10個“是/否”的問題得到結(jié)果。(圖1-2顯示如何只問4個問題就猜出1到16之間的某個數(shù)。)
為了避免反復(fù)問那些“是小于某個數(shù)嗎?”或者“是大于某個數(shù)嗎?”那樣乏味的問題,我們可以選擇問“是奇數(shù)嗎?”或“是偶數(shù)嗎?”。因為一個回答就可以讓我們排除一半的可能性。
類似的問題包括“十(百)位數(shù)是奇(偶)數(shù)嗎?”,像這樣的問題同樣可以使搜索空間(大致)縮小一半。不過要確認考慮了所有可能的數(shù),我們還得回到通常采用的減半方法(那些已經(jīng)被排除的數(shù)實際上已考慮在內(nèi))。
如果采用二進制表示數(shù),這個過程甚至會更簡單。十進制系統(tǒng)是用“10的乘冪的和”的形式表示數(shù),例如:
107 = 1·102 + 0·101 + 7·100
= 1·100 + 0·10 + 7·1
▲圖1-2 在1~16范圍內(nèi)猜出某個數(shù)的圖示
而在二進制系統(tǒng)中數(shù)是用“2的乘冪的和”的形式表示的:
107 = 1·26 + 1·25 + 0·24 + 1·23 + 0·22 + 1·21 + 1·20
= 1·64 + 1·32 + 0·16 + 1·8 + 0·4 + 1·2 + 1·1
因此107的二進制表示為1101011。要猜出一個二進制表示的數(shù)只要知道它最多多少位就足夠了。位數(shù)用以2為底的對數(shù)很容易計算。如果猜一個1到1000之間的數(shù),可以計算如下:
log2 1000≈9.97(向上取整)
也就是說共有10位。因此問10個問題足夠了:“第1位數(shù)是1嗎?”“第2位數(shù)是1嗎?”“第3位數(shù)是1嗎?”等等。最后所有位都知道了還必須轉(zhuǎn)換為十進制數(shù),用一個掌上的計算器就能解決了。
02 插入排序
我們要把書架上所有的書按照書名排序,這樣需要哪本書時很快就能找到。
如何快速地實現(xiàn)排序呢?我們可以有幾種不同的想法。例如我們可以依次查看每本書,一旦發(fā)現(xiàn)兩本緊挨著的書的次序不對就交換一下位置。這種想法能行,因為最終任何兩本書的先后都不會錯,但這平均要花費太長的時間。
另一種想法是先找出書名最“小”的那本書放在第一個位置,然后在剩下的書中再找出最“小”的放在緊挨著的后面位置,以此類推直到所有書都放在了正確的地方。這種想法也能行;但是由于大量有用的線索沒有利用,多花費了許多時間。下面我們試試其他的想法。
下面的想法似乎比上面討論的更加自然。第一本書自然是排好的。接下來我們拿第一本書的書名與第二本書的書名做比較,如果次序不對就交換兩本書的位置。然后我們看下一本書在前面已經(jīng)排好序的部分中應(yīng)該放在什么位置。
這可以反復(fù)進行直到為所有的書安排了正確的位置。因為前面的書排序時提供的信息可供后面使用,這個方法應(yīng)該效率高一些。
現(xiàn)在把這個算法再細細看一下。第一本書單獨考慮可以看作排好了序。我們假設(shè)當前考慮的書是第i本書,而它左邊所有的書都已排好序了。要將第i本書加入序列中,我們首先查找它正確的位置,隨后將書插入即可;為此要將在正確位置右邊的所有書向右移動一個位置。
接下來對第i + 1本書重復(fù)以上過程,以此類推直到所有的書放到了正確位置。這個方法能快速產(chǎn)生正確結(jié)果,特別是如果我們采用第1章介紹的二分搜索尋找正確插入位置則效果更明顯。
我們現(xiàn)在來看看對任意數(shù)量的書,這個直觀的方法如何實現(xiàn)。為了描述起來簡單一些,我們用數(shù)字代替書名。
圖2-1中左邊的5本書(1,6,7,9,11)已經(jīng)排好序,而書名為5的書位置不正確。為了將5放入正確位置,首先與11交換位置,再與9交換位置,以此類推直到5到達正確位置。然后我們再處理書名為3的書,同樣通過與左側(cè)的書交換來到達正確位置。顯然最終所有的書都會放到正確的地方(見圖2-2)。
▲圖2-1 前5本書已排好序
▲圖2-2 書名為“5”的書移動到正確位置
以下是算法的代碼。這里使用數(shù)組A,其元素標號為1,2,3,…。A[i]表示數(shù)組中第i個元素的值。給n本書排序使用長度為n的數(shù)組,元素A[1],A[2],A[3],…,A[n-1],A[n]存放所有的書名。
現(xiàn)在考慮算法執(zhí)行花費的時間。我們考慮最壞的情況,所有書放置的位置正好與期望的次序相反,即書名最小的在最后的位置上,而書名最大的卻在最前面的位置上。
我們的算法讓第1本書與第2本書交換位置,第3本書要和前兩本書中每一本交換位置,第4本書則要和前面3本書中每一本交換位置,以此類推,最后的一本書得和前面n-1本書中的每一本交換位置。交換的總次數(shù)是:
1+2+3+...+(n-1)=n(n-1)/2
利用圖2-3很容易推導(dǎo)出上述公式。整個矩形中含n·(n-1)個單元格,其中一半用于比較與交換。圖中顯示的是絕對的最壞情況。考慮平均情況,我們可以假設(shè)只需要一半的比較與交換。
如果開始時書就幾乎是排好序的,需要的工作量會少很多;最好的情況是開始時所有的書都在正確的位置上,那只需要進行n-1次比較即可。
▲圖2-3 計算交換次數(shù)
你也許會看出算法還可以更簡潔些。不用交換相鄰的兩本書,而是將多本書向右移動,使得需要的插入位置空出來。如果2-4所示。
原來的k次兩兩置換操作,現(xiàn)在可以用k + 1次移動一本書的操作替代。算法修改如下:
▲圖2-4 計算交換次數(shù)
盡管在串行的計算機上此算法排序效率不高,但它的實現(xiàn)非常簡單,所以當需要排序的對象數(shù)量不太大,或者可以假設(shè)多數(shù)對象次序不錯的情況下還是會經(jīng)常使用插入排序算法。要對大量對象進行排序就會使用其他算法,如mergeSort和quickSort。那些算法理解起來會難一些,實現(xiàn)也更復(fù)雜。
關(guān)于作者:本書共有66位作者,主要來自德國、瑞士。由貝特霍爾德·弗金(Berthold V?cking)、赫爾穆特·阿爾特(Helmut Alt)、馬丁·迪茨費爾賓格(Martin Dietzfelbinger)、呂迪格·賴舒科(Rüdiger Reischuk)、克里斯蒂安·沙伊德勒(Christian Scheideler)、黑里貝特·沃爾默(Heribert Vollmer)、多蘿西婭·瓦格納(Dorothea Wagner)領(lǐng)銜編著。
本文摘編自《無處不在的算法》,經(jīng)出版方授權(quán)發(fā)布。
延伸閱讀《無處不在的算法》
點擊上圖了解及購買
轉(zhuǎn)載請聯(lián)系微信:togo-maruko
推薦語:杰出計算機教育家南京大學陳道蓄教授翻譯并推薦,啟蒙學生對計算機科學興趣、提升計算思維素養(yǎng)的入門讀本。
據(jù)統(tǒng)計,99%的大咖都完成了這個神操作
▼
更多精彩
在公眾號后臺對話框輸入以下關(guān)鍵詞
查看更多優(yōu)質(zhì)內(nèi)容!
PPT?|?報告?|?讀書?|?書單
大數(shù)據(jù)?|?揭秘?|?人工智能?|?AI
Python?|?機器學習?|?深度學習?|?神經(jīng)網(wǎng)絡(luò)
可視化?|?區(qū)塊鏈?|?干貨?|?數(shù)學
猜你想看
機器學習重大挑戰(zhàn):壞數(shù)據(jù)和壞算法正在毀掉你的項目
違背常識、顛覆認知,終于有人把薛定諤的貓講明白了
干貨:用Python進行數(shù)據(jù)清洗,這7種方法你一定要掌握
極度燒腦+驚人發(fā)現(xiàn):4個顛覆你世界觀的量子理論實驗
Q:?這些技能你都掌握了嗎?
歡迎留言與大家分享
覺得不錯,請把這篇文章分享給你的朋友
轉(zhuǎn)載 / 投稿請聯(lián)系:baiyu@hzbook.com
更多精彩,請在后臺點擊“歷史文章”查看
點擊閱讀原文,了解更多
總結(jié)
以上是生活随笔為你收集整理的写给中学生的算法入门:学代码之前看这篇就够了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Python玩转统计数据:取样、计算相
- 下一篇: 《三国演义》社交网络数据分析:最重要的一