之前在微博 @演算法時空 做了一次電臺,花了一個多小時談了一下Sedgewick和Wayne所著的暢銷書《演算法》第4版(影印版和中譯版均由人民郵電出版社出版),特別是按照這本書的目錄給出了導讀。覺得有必要把文字整理出來,希望對閱讀此書的朋友有所幫助。
歷史
《演算法》第4版這本書其實不太像傳統的演算法書,但是它很暢銷!實際上,這不僅因為它有接近四十年的傳承,多次修訂不斷進化方才如此,而是作者的最新教學理念的展現。
演算法分析大師Sedgewick一開始寫這個系列的書,心中就有巨集偉的念頭,要傳承Knuth的衣缽,因為Sedgewick作為Knuth的學生,他覺得當仁不讓,所以雄心勃勃。其實Sedgewick剛開始開始寫《演算法》的時候,也就是《演算法》第1版,內容相對比較簡單。隨著時間流逝,第2版和第3版不斷進化,而此時這套書的難度到達了巔峰。
實際上《演算法》第3版出過很多語言版本,比如C++
, C
, Java
版(國內高教出版社影印過)。最開始是C
, C++
然後是Java
,其實Sedgewick想把Knuth難度極高的《計算機程式設計藝術》三卷書濃縮成《演算法》的上卷(或稱Part 1-4),並用不同語言來實現,從而形成更適合教學的優秀教科書。這本上卷名為《演算法與資料結構基礎、排序和查詢》,其內容非常接近《計算機程式設計藝術》的第1卷(基本演算法)和第3卷(排序與查詢),去掉了第2卷(因為一般大家都不看第2卷,裡面講的是隨機數生成等內容)。《演算法》的下卷(或稱Part 5),從《計算機程式設計藝術》往下開始寫,專講圖演算法,雖然比上卷薄,但內容依然很豐富。
變革
Sedgewick花了這麼多年將這套《演算法》做到了很高的層次,為什麼寫到第4版的時候,思路有了一個如此大的轉變呢?實際上他在前言裡說到,第4版的難度相當於第1版或者第2版的樣子,回覆到一個基礎簡單的水平,也是Addison-Wesley出版社的Peter Gordon建議他要back to the basics。
《演算法》第4版的核心寫作思想就是降低演算法學習的難度,這是一種大勢所趨,實際上寫到了巔峰沒幾個人能看懂。就拿Knuth的三卷《計算機程式設計藝術》來說吧,很多人看到數學知識太繁雜,演算法分析長篇大論,而且Knuth有點強迫症(不過他創造的TeX排版確實太好了),書裡用MMIX,讀者還得學這個。實際上,《計算機程式設計藝術》這樣一個高大上的體系讓Knuth奉獻了一生,特別是裡面的演算法分析,數學推導特別多。但是,Knuth的得意門生Sedgewick在這樣的時代卻寫了一本難度比較低的演算法書,實際上是有很多無奈的。
Google的Peter Norvig說Knuth的三卷《計算機程式設計藝術》可以墊高顯示器,由於盒裝可以從裡面抽出一本隨時翻閱。但更多的人拿這個墊顯示器估計不會拿出來看了。
前幾年的Sedgewick的個人網站還有《演算法》第3版後續部分也就是組合演算法部分的寫作計劃,和老師Knuth的思路完全一樣。這兩年這部分寫作計劃似乎取消了,可能寫出來太耗時,曲高和寡沒人看。最終Sedgewick決定讓演算法成為新時代大家都能接受的東西,切實能夠提高程式設計師水平,而不是高深的理論和繁難的技術。老實說,很多人根本用不到那麼多演算法,所以《演算法》第4版看似思路清奇但合情合理。
《演算法》居然沒有講動態規劃,你說這叫演算法書嗎?當然可以叫演算法書,它其實就不太注重動態規劃這些內容,其實普通人也用不太上。
另外,複雜的數學語言《演算法》第4版裡都沒有,而Sedgewick本人演算法分析功底相當深厚。我相信他這樣的大師,肯定能瞭解普通人接受起來有困難,所以就放下了自己擅長的理論分析。所以,經過四十年風風雨雨,最後變成了《演算法》第4版,精選了普通程式設計師確實能用的內容,確實不易。
這本書對我的教學觀有很大的影響,也激發了我開設“演算法時空”知識星球。以前我講演算法的時候,沒事喜歡推導一下大O記號之類,動不動寫個公式求個極限,給出比較高深的證明,可能是受到《演算法導論》這種書的影響。但我現在好像越講越簡單了,力圖讓大家多少有點收穫吧。
Sedgewick在寫這本書的時候,得到了第二作者Wayne的大力協助。Wayne是個藝術天賦很高的人,不太醉心於科研而特別喜歡講課,他博士師從康奈爾大學的Tardos,畢業之後就一直積極開展教學工作,另外還給Kleinberg和Tardos的《演算法設計》做了課件(官方指定版),可能Wayne的課件做得太好了吧。所以《演算法》第4版排版特別清新,而且是雙色印刷,Wayne絕對功不可沒。另外,國內影印版印刷質量很不錯,我感覺紙張比原版還要厚實,可能原版有點薄還有反光,不知道紙張到底如何選取的。
Kevin Wayne is the Phillip Y. Goldman Senior Lecturer in Computer Science at Princeton University, where he has taught since 1998, earning several teaching awards.
下面來看看《演算法》第4版的構成,從目錄講起。
第1章 基礎知識
1.1 程式設計模型,主要討論Java基礎知識和二分查詢。因為這本書前期有Java程式設計的課程,所以1.1篇幅很短。主要是Java程式設計師太多了,所以Sedgewick沒有在《演算法》第4版用C++這樣的語言。順便提一下,現代C++如果只用簡單的語法部分也不是特別難,而且效能非常優秀。
1.2 資料抽象,也就是所謂抽象資料型別(ADT)。其實抽象資料型別在資料結構課程裡都學過,但很多人對它的理解不深刻,處理演算法問題應該在抽象資料型別的層次上來做。比如你拿到了集合這樣的抽象資料型別,所有資料在裡面,而集合是個黑盒我們不用操心,只需要呼叫集合的介面來使用即可。其實資料結構教學的趨勢早已如此,不過國內的教學還沒有完全與之一致。有了抽象資料型別之後,所有的處理都在抽象資料型別上展開,我們不需要會實現資料結構,只要能用抽象資料型別並且知道其原理和效能即可,也就是介面與實現分離。
1.3 這節是與傳統資料結構講解完全不一樣的地方,以前大家都會講很多資料結構,而實際中真正有用的卻不是那麼多。《演算法》第4版就精選了包、佇列和棧。包就是不用操心其中元素次序的抽象資料型別,放進去當儲藏室就可以了,內部實現其實是連結串列但不提供刪除。佇列和棧很常用,我們就不多說了,另外如何高效實現佇列我們其實也不用操心。所以,《演算法》第4版一開始就抽象和提煉了三個抽象資料型別(注意不是資料結構),有了抽象資料型別的基礎就可以無腦使用,但是要知道佇列是FIFO而棧是LIFO的特性。這一節相當贊,一開始學習不會讓讀者涉獵太多的資料結構,學習難度大大降低。
說實話《演算法》第4版的寫作思路和當前的現實有關,很多人不願意去學習那些複雜繁瑣的東西,這是大趨勢。怎麼辦呢?可以簡化內容去講一些最有用的東西,把精力投入其它事情上去,初學資料結構要掌握的從原來的複雜多樣到現在的簡單明瞭,就講三個!
1.4 演算法分析。這節篇幅非常短,不到30頁。你可以想象這樣一位演算法分析大師在寫本節的時候,是什麼樣的心情。明明有很多想寫出來的公式,很多想告訴學生的高深內容,但Sedgewick一個都不寫。他完全沒有寫從理論到理論的模型,也就是《演算法導論》還有Aho等人的《演算法設計與分析》那種體系,這些書首先考慮三種情況(最壞、最好和平均),以大O記號描述,並主要以最壞情況來討論,Sedgewick在《演算法》第4版裡特別隱忍,這是不太容易的。大部分在演算法分析上有所造詣的人可能都忍不住想講解這些內容,但是Sedgewick就忍住了。他怎麼做的呢?偏重於科普,讓讀者瞭解物理直覺。只要知道大概什麼樣的演算法更快、什麼更慢,這就可以了。Sedgewick用了一種做實驗的方法,觀察演算法的執行快慢並建立模型。可以看到《演算法》第4版裡只提到量級(實際上接近於Theta記號),連大O記號都不用,只用簡單語言簡化描述,並用圖示刻畫函式的增長,另外用加倍實驗直觀展示了增長量級。一言以蔽之,讓讀者知道只需要瞭解這麼多就可以了。這種想法看起來很奇怪,但其實很有道理,因為平時能用到的大O記號就那麼幾種,知道它們就可以了,不用太過於深入理論知識,頂多再瞭解一些極限的求解即可。我覺得,對於演算法分析大師來說寫這節真的很痛苦。不過Sedgewick把基本思想寫進去了,而且用簡單語言描述。《演算法》第3版還是寫了很多演算法分析的基礎知識,還有遞推式的內容,但《演算法》第4版全都去掉了。儘量用通俗的語言讓更多人瞭解演算法分析。
一般演算法書上都會對各種不同量級的實測時間給出直觀的例子。對於較大的問題規模:線性演算法比較快,線性對數演算法也不錯,平方演算法慢多了,指數演算法永遠沒法完成。
1.5 有了前面資料結構的內容和演算法分析的基礎,接下來馬上講實際案例可以讓人體會理論的力量。這節討論了合併—查詢演算法,也就是如何快速實現等價類,所用的資料結構看起來是樹,但實際只需要父親結點陣列就可以描述。可以看出,用了優秀的演算法可以極大地提升效能。其實合併—查詢的思路和想法都很樸素簡單,但演算法分析特別困難,也就是那種看似很簡單其實不然的典型例項。Sedgewick用這個很好的例項來說明,好的演算法是怎樣能提升效能的。實際上, 《演算法》第3版就是如此安排, 而《演算法設計》這本書也仿效這個在一開始講合併—查詢的設計,說明這個案例確實特別經典,而且適合初學者入門。
第2章 排序
第2章和第3章著重討論排序和查詢,一眼就能看出來用的是Knuth《計算機程式設計藝術》第3卷的體系,而這也是Sedgewick精心研究的內容。
一開始講了幾個簡單的排序演算法,也就是插入排序和選擇排序這些平方時間的排序,我覺得這幾種演算法練練手就可以了。另外《演算法》第4版給出了排序演算法的視覺化,現在資料結構和演算法的視覺化也是相當重要的(推薦VisuAlgo:visualgo.net/),資料到底如何變化用直觀方式就可以學明白。
前一段時間有人在微博上問我Shell排序的一個細節問題。說實話,這些排序演算法現在看得很少,能不講就不講,這些東西平時也不用,效能也一般。其實也失去了講解的意義,沒事看看就好了。
基礎的排序我們就不談太多,接下來我們就看看線性對數時間量級的排序演算法。
2.2 歸併排序,實現方式有兩種:自頂向下的遞迴實現和自底向上的實現。歸併排序看起來沒什麼太大的用處(因為它不是特別快),但在外存排序裡非常有用,而且它基本上是少數幾個外存排序裡最主流和最實用的一種了,其他排序演算法基本都用不上。我所翻譯的《演算法設計指南》裡面有個War Story講了一點外存排序的思想。最後談了一下排序問題的複雜度,也就是排序演算法的線性對數下界,講到這裡相信大家會有一點對排序問題的本質理解了。
2.3 快速排序,快速排序大家都要講,而《演算法》第4版講了改進。有時間的話,建議大家可以看看不同版本的標準庫實現(特別是clang),看看這些庫究竟是怎麼實現的。實際上,自己實現的快速排序演算法效能一般不太好,特別是在處理遞迴呼叫比較多的時候(可以試試10億個浮點數),尾遞迴太多容易棧溢位。
看了標準庫的實現之後,就會明白什麼是理論與工程的完美結合,而快速排序是一個特別好的例子。例如這個
qsort
的實現:opensource.apple.com//source/xnu…
2.4 優先順序佇列和堆排序。實際上優先順序佇列是非常有用的抽象資料型別,有一篇小論文說到荒島上你會帶什麼唯一的抽象資料型別,答案就是優先順序佇列。
論文名:If you were lost on a desert island, what one ADT would you like to have with you? 優先順序佇列可以實現棧,也可以實現佇列,只需要用時間為優先順序即可。
優先順序佇列的變化還是相當多的,可以深入瞭解這方面的知識,例如可以參考Handbook of Data Structures and Applications。有了優先順序佇列之後,接著講堆排序,這裡不再多說,給一個堆排序的實現(opensource.apple.com/source/Libc…)。
2.5 這節的關鍵是該使用哪種排序演算法,什麼時候用什麼排序,這個問題很重要。
排序講到這裡就結束了,最有用的就是三種:歸併排序、快速排序和堆排序,講得很簡化。其實我覺得可以更極端一點,基礎的排序只需要知道這兩點即可:插入排序在小資料情況很快;選擇排序可以過渡到堆排序。其他平方時間的排序都可以不講了,反正用處也不是很大。
實際上,學堆排序更大的用處是為了讓你瞭解和掌握優先順序佇列這種抽象資料型別。快速排序是為了讓你瞭解隨機化演算法。歸併排序是外存演算法,儘可能少做內外存交換(但不可能完全用記憶體處理)。
也就是說,我們從排序這章要學一些演算法思維和工程思想。
第3章 查詢
排序和查詢為何如此重要,Knuth在《計算機程式設計藝術》第3卷提到大多數主機的時間都在進行排序和查詢,而查詢對於我們來說更為常見。查詢部分的內容首先從符號表開始,所謂符號表就是一個"鍵—值"的集合,而查詢就是用鍵去查值。
3.2和3.3 第一種思路是最壞時間所有操作都能在對數時間內完成的樹查詢結構,一般要完成插入、刪除和查詢,它們都在可以對數時間內完成。先用二叉查詢樹,但是它在最壞情況下達不到對數時間而退化成連結串列,基本原因是不平衡也就是樹太高了。為了平衡用了兩種方法就是2-3樹和紅黑樹,有的書上會講AVL樹但《演算法》第4版放在習題裡了。
我個人認為,紅黑樹其實也不用掌握,一般人知道有這麼一種結構可以高效實現集合就可以了,效率就是對數時間,而且是最壞情況的保證。
3.4 不過對數時間雖然比較快,而且最壞情況有保證,但真去查詢起來有時候不如雜湊。如何調整雜湊是一個比較技術性的內容。很多人有這樣的誤解,雜湊的查詢在期望時間是常數時間,那全部都用雜湊就好了。很多語言比如Python
都提供了字典,而且是常數時間,用起來很方便,好像很厲害。但最壞情況下會退化成線性時間,但是一定要有所選擇,特別是最壞情況有要求。當然,還有更多高階技術,可以改進雜湊。
一定不能一提到雜湊就馬上認為是常數時間特別好,要有選擇地使用。而且《演算法》第4版也講了如何選擇雜湊還是樹結構。沒有免費午餐(No Free Lunch)!
看起來查詢部分內容不多,其實我們大家平時用的也就是這些抽象資料型別,比如C++裡也就是set
(紅黑樹實現)和unorder_set
(雜湊實現)而已,其他語言也都有類似這樣的抽象資料型別,所以用其他語言也可以看《演算法》第4版,不影響對演算法實質的掌握。
第4章 圖
前面講完直接跳到圖演算法,圖演算法在《演算法》第4版的篇幅也不是很多,其實很多人在實際工作中也用不到特別深入的圖演算法,真正要用的時候又可能一籌莫展。於是就有這樣的難題:到底圖演算法要學到什麼層次,教材又該如何選擇教學內容呢?
4.1 無向圖,這裡講道了深度優先搜尋和廣度優先搜尋,裡面講的最多是迷宮。迷宮到底用DFS還是BFS呢?讀者不妨考慮一下。下來是連通分量。這些都是圖論裡的簡單內容,但是能提升讀者的圖演算法思想。隨後講了有向圖、可達性和強連通分量,特別重要的就是強連通分量(SCC)演算法,而這是《演算法》第4版裡比較難的內容了(其實一般人也不要學網路流了,學一些基本圖演算法就夠了)。
物理學家黃昆說道:學習知識不是越多越好、越深越好,而是應當和自己駕馭知識的能力相匹配。這句話放在演算法學習特別是圖演算法的學習是相當合適的。
4.3 最小生成樹,主要是Prim演算法和Kruskal演算法。特別是Kruskal演算法又用到了合併—查詢,這裡可以看到資料結構的優化在圖演算法中能起到很重要的作用,提速特別明顯。要注意,有些演算法思想不一定今天能用到,但你的思路改進了,思想開闊了,將來就有可能用到,最差也可以感受一下演算法之美。
選擇一本演算法書的基準是看看圖的表示方法,如果不能正確使用鄰接表描述圖演算法,那麼說明作者的圖演算法沒有入門。很多教材用鄰接矩陣描述,而主流的演算法設計以及分析都應該建立在鄰接表上。
4.4 最短路徑。這裡不多說最短路徑的內容了,舉個例子,平時我們叫車用最短路徑,如果是時長的話可以考慮最短時長路徑的求解。
第5章 字串
對很多程式設計師更有用的其實是字串的處理,一般演算法書講得少,覺得似乎不是特別高階,不如動態規劃炫酷,但《演算法》第4版著重講解了這部分內容。
5.1 一開始講的可以認為是針對多鍵(multiple keys)或者多個資料域的排序。對於字串來說,低位優先(LSD)可以更快地對等長的字串來排序,而不會去用快速排序這些普適演算法,這樣處理字串更快,而字串的取值空間有限特性很重要。而不等長的可以採用高位優先(MSD),後面進一步改進成字串的三路快速排序,深入探討了字串排序。
Bentley和Sedgewick的論文Fast Algorithms for Sorting and Searching Strings可以深入研究(www.cs.princeton.edu/~rs/strings…),闡述了Multikey Quicksort的原理並分析了效能。另外,Sedgewick的講義Advanced Topics in Sorting(www.cs.princeton.edu/~rs/AlgsDS0…)有關於排序的一些高階主題。
5.2 trie,也就是單詞查詢樹。搜尋框就是簡單的trie,比如想輸入abstract
,那麼依次輸入a-b-s-t
,先從樹上走a
這個分支,再走b
隨後走s
繼續走t
分支,最後剩下的以abst為字首的單詞也沒剩幾個了,很容易找到abstract這個單詞,注意這種實現需要26叉樹(可用ternary search trie改進之)。trie非常有用,還有字尾樹和字尾陣列等內容也可以作為選學材料。
5.3 字串的查詢,所謂模式匹配,Sedgewick強調的是後面的一系列演算法(當然不能繞過他老師的KMP演算法),例如Boyer-Moore演算法和Rabin-Karp演算法,這兩種更有用而且更快。KMP強烈依賴於自我的模式,要自身重複,但很多字串不具備這些特性,而Boyer-Moore或Rabin-Karp更適合於一般的字串查詢。
5.4 講完上述內容就開始討論正規表示式。又一次說明了字串這章對實際程式設計師更有用,一般演算法教材講的圖演算法還有動態規劃對於普通程式設計師來說,要想用好其實很難,而字串卻經常能感受到。
5.5 本章結尾講到了資料壓縮,這部分是非常好的演算法應用場景。像CMU的"真實世界的演算法"這門課程裡講了很多資料壓縮的演算法(還有糾錯編碼和線性規劃),也就是實際演算法可以看到很多字串的處理,又比如Huffman編碼用到了優先順序佇列,處理資料可以用到trie還有雜湊,形形色色演算法的應用讓你親身體驗演算法之大用。其實,資料壓縮不是太難,自己如果可以很快實現壓縮軟體會有一定成就感。我講資訊理論課程的時候會讓學生做一般文字檔案的資料壓縮,看看壓縮和解壓的效率與常用軟體如Winzip或者7zip有什麼效能差異,這樣能極大地提升學習興趣。此外,文字壓縮還有一些字典系列的編碼(7zip的體系),還會有更多演算法與資料結構的應用,特別是雜湊還有滑動窗的設定,如果能實現基本的LZ77和LZ78,那麼演算法瞭解和應用又能上一個臺階。我也借鑑《演算法》第4版的一些特點,讓學生實現DNA序列的壓縮,這樣會有趣味性,也更有針對性。
CMU的15-853: Algorithms in the Real World這門課程(www.cs.cmu.edu/~guyb/realw…)非常值得一看,非常適合進階學習。
第6章 實境
《演算法》第4版前五章的內容很精煉,和其他演算法書都不一樣,也許稱之為《資料結構與演算法》更合適一點,因為講資料結構的內容較多。
第6章就是講真實的問題,並由此引出前面的演算法和指導讀者應該學習什麼樣的內容。在真實問題的背景下把前面的內容拿出來再講,其實效果非常好。
典型例子是離散事件模擬(DES),例如公交車的排程模擬要考慮某個線路何時發車。發車相當於一個"事件",有很多車會發車但時間不同,我們不是按照固定時間間隔(例如分鐘)向前逐個處理和方針,而是處理"事件"並將其放入優先順序佇列,只需按照事件發生時間先後取出並處理,最早出現的事件肯定最先出隊,這樣能夠極大提升演算法模擬速度。不能按時間間隔去逐個處理,這樣特別慢,比如當前時間為6:30而如果下一個事件7:10出現,那麼時間點直接推進到7:10即可。
語言選用
《演算法》這個系列的書最開始用C
語言,可能是想讓他老師Knuth的書更簡單容易讀,另外那個年代C
還是比較流行的。後來大家用C++
,Sedgewick也推出了相關版本,並且也推進到Java
版本。但第4版不標註語言版本直接用Java
,也說明Java
的熱度,實際上沒有提到什麼語言也說明不想寫別的語言版本了。
不過,現在用Python
也很多而且也更接近於機器學習和資料處理,這個其實很合理,一門語言學好了能做很多事情,所以都去學Python
。而Sedgewick緊跟時代,又出了專門講Python
的教材,我本來覺得第5版很可能就是Python
版(假設有第5版)。因為前期的Python
基礎的書已經有了,程式設計的知識講過了,後面直接用Python
講演算法課而且還可以做機器學習,這也是MIT多年講《演算法導論》的首選語言,大勢所趨嘛,而且實現起來方便。最關鍵的是,很多人不願意用複雜的語言解決問題,現在的人越來越懶:-)而且重度依賴於機器,沒事不用C
和C++
寫程式。
為了求證這個Python版本的猜測,我郵件求證了Wayne,他說暫無
Python
版本的寫作計劃,其原因是用Python
寫的程式碼遠遠慢於Python
自身提供的庫函式,這樣起不到展示演算法和資料結構效率的目的。
排版
實際上排版是《演算法》第4版的一大特色,第3版用LaTeX排版,而第4版居然用InDesign排版,但是雙色印刷相當精美細緻。主要是公式很少,所以用了InDesign。
我郵件諮詢過Wayne,這麼複雜的圖能用LaTeX排出來麼?他的回覆讓我很詫異,居然是用InDesign排版,另外這些精美的插圖向量圖是拿AI畫的,所以融合起來用Adobe一家的產品更好,保持一致。實際上從成書效果來看,排版確實美輪美奐,非常滿意。
當然也是因為《演算法》第4版的公式少,實際上這本書基本不講公式,能不用就不用,這點節約了大家的腦力。因為數學確實會給很多人帶來困擾,實際上數學讓人會有特別深的恐懼感。演算法再加數學更讓人害怕了,所以《演算法》第4版用到了演算法執行實況(到底如何執行,一步步告訴大家)和視覺化的方法。
《演算法》第4版和前3版有將近40年的傳承,而第二作者Wayne為這一版本付出了相當大的心血,這點很難得(絕大多數高校教師因為要做科研所以做不到這點,而且也沒有這麼多精力來精心編撰教材),而Wayne投入了很多精力放在這本書上。不過,從繪圖和排版軟體的選擇上來說,還是比較符合這本書的目的,主要能更好服務於普通讀者,一看就不是特別難,而且又是彩色印刷,所以很能吸引眼球。
Q & A
- 先修課程是什麼?有一點離散數學知識就可以了,《演算法導論》後面的附錄基本也就夠了,可以放心學《演算法》第4版。
- 要學什麼數學?學別的演算法書,離散數學是要學的,高等數學也是要學的,概率論也是不能丟的,線性代數也得非常好才行,矩陣如果不會好多東西用不成。但《演算法》第4版裡基本沒有什麼矩陣,哈哈。當然,多學一點離散數學更好,但是要看個人能力而定。既然不能學複雜的內容,那就吸收點有用的東西讓程式提升吧,一定要養成很好的品味,有好壞的演算法之分,這點很重要。
- 多久能看完?不要指望很快看完。
- 應該買中文版還是英文版?英文教材和課程其實學起來還是有點難度,所以大家根據自己需要和能力範圍選擇購買中文版或英文版。
- 寫程式的態度應該如何?儘量少寫低效的演算法,甚至於低效的程式,要儘量提高程式的效能。
《演算法》第4版,幫助你在平常而又不平凡的程式設計裡找到更多樂趣!
我看了一個電影說小女孩學數學壓力過大,她母親為了解開世界難題自殺了,