《算法》第4版 導讀

《算法》第4版

以前在微博 @算法時空 作了一次電臺,花了一個多小時談了一下Sedgewick和Wayne所著的暢銷書《算法》第4版(影印版和中譯版均由人民郵電出版社出版),特別是按照這本書的目錄給出了導讀。以爲有必要把文字整理出來,但願對閱讀此書的朋友有所幫助。html

歷史

《算法》第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版看似思路清奇但合情合理。數據結構

《算法》竟然沒有講動態規劃,你說這叫算法書嗎?固然能夠叫算法書,它其實就不太注重動態規劃這些內容,其實普通人也用不太上。app

另外,複雜的數學語言《算法》第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.23.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多年講《算法導論》的首選語言,大勢所趨嘛,並且實現起來方便。最關鍵的是,不少人不肯意用複雜的語言解決問題,如今的人愈來愈懶:-)並且重度依賴於機器,沒事不用CC++寫程序。

爲了求證這個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版,幫助你在日常而又不平凡的程序設計裏找到更多樂趣!

我看了一個電影說小女孩學數學壓力過大,她母親爲了解開世界難題自殺了,

相關文章
相關標籤/搜索