胡侃學習(理論)計算機【被大佬推薦,轉載以膜拜】
《胡侃學習(理論)計算機》
作者: Sir (阿澀)
我也來冒充一回高手,談談學習計算機的一點個人體會。由於我是做理論的,所以先著重談談理論。
記得當年大一,剛上本科的時候,每週六課時數學分析,六課時高等代數,天天作業不斷(那時是六日工作制)。頗有些同學驚呼走錯了門:咱們這到底唸的是什麼系?不錯,你沒走錯門,這就是(當時的)南大計算機系。系裡的傳統是培養做學術研究,尤其是理論研究的人。而計算機的理論研究,說到底了就是數學,雖然也許是正統數學家眼裡非主流的數學。
數學分析這個東東,咱們學計算機的人對它有很複雜的感情。愛它在於它是第一門,也是學分最多的一門數學課,又長期為考研課程。94以前可以選考數學分析與高等代數,以後則並軌到著名的所謂"工科數學一"。其重要性可見一斑。恨它則在於它好像難得有用到的機會,而且思維跟咱們平常做的這些離散/有限的工作截然不同。當年出現的怪現象是:計算機系學生的高中數學基礎在全校數一數二(希望沒有冒犯其它系的同學),教學課時數也僅次於數學系,但學完之後的效果卻幾乎是倒數第一。其中原因何在,發人深思。
我個人的淺見是:計算機類的學生,對數學的要求固然跟數學系不同,跟物理類差別則更大。通常非數學專業的所謂"高等數學",無非是把數學分析中較困難的理論部分刪去,強調套用公式計算而已。而對計算機系來說,數學分析裡用處最大的恰恰是被刪去的理論部分。說得難聽一點,對計算機系學生而言,追求算來算去的所謂"工科數學一"已經徹底地走進了魔道。記上一堆曲面積分的公式,難道就能算懂了數學分析?
中文的數學分析書,一般都認為以北大張築生老師的"數學分析新講"為最好。我個人認為南大數學系的"數學分析教程"也還不錯,至少屬於典型的南大風格,咱們看著親切。隨便學通哪一本都行。萬一你的數學實在太好,這兩本書都吃不飽,那就去看菲赫金哥爾茨的"微積分學教程"好了--但我認為沒什麼必要,畢竟你不想轉到數學系去。
吉米多維奇的"數學分析習題集"也基本上是計算型的東東。如果你打算去考那個什麼"工科數學一",可以做一做。否則,不做也罷。
中國的所謂高等代數,就等於線性代數加上一點多項式理論。我以為這有好的一面,因為可以讓學生較早感覺到代數是一種結構,而非一堆矩陣翻來覆去。當年我們用林成森,盛松柏兩位老師編的"高等代數",感覺相當舒服,我直到現在還保留著教材。此書相當全面地包含了關於多項式和線性代數的基本初等結果,同時還提供了一些有用的比較深的內容,如Sturm序列,Shermon-Morrison公式,廣義逆矩陣等等。可以說,作為本科生如能吃透此書,就可以算高手。後來它得以在南大出版社出版,可惜好像並軌以後就沒有再用了。
國內較好的高等代數教材還有清華計算機系用的那本,清華出版社出版,書店裡多多,一看就知道。特點嘛,跟南大那本差不太多。
但以上兩本書也不能說完美無缺。從抽象代數的觀點來看,高等代數裡的結果不過是代數系統性質的一些例子而已。莫宗堅先生的"代數學"裡,對此進行了深刻的討論。然而莫先生的書實在深得很,作為本科生恐怕難以接受,不妨等到自己以後成熟了一些再讀。概率論與數理統計這門課很重要,可惜少了些東西。
少了的東西是隨機過程。到畢業還沒有聽說過Markov過程,此乃計算機系學生的恥辱。沒有隨機過程,你怎麼分析網路和分散式系統?怎麼設計隨機化演算法和協議?據說清華計算機系開有"隨機數學",早就是必修課。人家可是工科學校,作為自以為"理科計算機系"出身的人,我感到慚愧。
另外,離散概率對計算機系學生來說有特殊的重要性。現在,美國已經有些學校開設了單純的"離散概率論"課程,乾脆把連續概率刪去,把離散概率講深些。我們不一定要這麼做,但應該更加強調離散概率是沒有疑問的。
計算方法是最後一門由數學系給我們開的課。一般學生對這門課的重視程度有限,以為沒什麼用。其實,做圖形影象可離不開它。而且,在很多科學工程中的應用計算,都以數值的為主。
這門課有兩個極端的講法:一個是古典的"數值分析",完全講數學原理和演算法;另一個是現在日趨流行的"科學與工程計算",乾脆教學生用軟體包程式設計。南大數學系的幾位老師做了件大好事,把前者的一本極為經典的教材翻譯出版了:德國Stoer的"數值分析引論"。如果你能學會此書中最淺顯的三分之一,就算沒有白上過計算方法這門課!而後一種講法似乎國內還沒有跟上潮流?不過,只要你有機會在自己的電腦上裝個matlab之類,完全可以無師自通。
本系裡,通常開一門離散數學,包括集合論,圖論,和抽象代數,另外再單開一門數理邏輯。這樣安排,主要由於南大的邏輯傳統:系裡很多老師都算莫先生的門人,就連孫先生都是邏輯專業出身(見孫先生自述)。
不過,這麼多內容擠在離散數學一門課裡,是否時間太緊了點?另外,計算機系學生不懂組合和數論,也是巨大的缺陷。要做理論,不懂組合或者數論吃虧可就太大了。
從理想的狀態來看,最好分開六門課:集合,邏輯,圖論,組合,代數,數論。這個當然不現實,因為沒那麼多課時。也許將來可以開三門課:集合與邏輯,圖論與組合,代數與數論。
不管課怎麼開,學生總一樣要學。下面分別談談上面的三組內容。
古典集合論,北師大出過一本"基礎集合論"不錯。南大出版朱梧(木賈)老師的"集合論導引"也許觀點更高些,但他的書形式化得太厲害,念起來吃力。
數理邏輯,莫先生的書自然是經典。然而我們也不得不承認,此書年代久遠,光讀它恐怕不夠。尤其是命題/謂詞演算本身有好多種不同的講法,多看幾家能大大開闊自己的視野。例如陸鍾萬老師的"面向電腦科學的數理邏輯"就不錯。朱老師也著有"數理邏輯教程"一書,但也同樣讀起來費力些。
總的來說,學集合/邏輯起手不難,但越往後越感覺深不可測。建議有興趣的同學讀讀朱老師的"數學基礎引論"--此書有點時間簡史的風格,講到精彩處,所謂"天花亂墜,妙雨繽紛",令人目不暇接。讀完以後,你對這些數學/哲學中最根本的問題有了個大概瞭解,也知道了山有多高,海有多深。
學完以上各書之後,如果你還有精力興趣進一步深究,那麼可以試一下GTM系列中的Introduction to Axiomatic Set Theory和A Course of Mathematical Logic。這兩本都有世界圖書的引進版。你如果能搞定這兩本,可以說在邏輯方面真正入了門,也就不用再浪費時間聽我瞎侃了。
據說全中國最多隻有三十個人懂圖論(當年上課時陳道蓄老師轉引張克民老師的話)。此言不虛。圖論這東東,技巧性太強,幾乎每題都有一個獨特的方法,讓人頭痛。不過這也正是它魅力所在:只要你有創造性,它就能給你成就感。所以學圖論沒什麼好說的,做題吧。
國內的圖論書中,王樹禾老師的"圖論及其演算法"非常成功。一方面,其內容在國內教材裡算非常全面的。另一方面,其對演算法的強調非常適合計算機系(本來就是科大計算機系教材)。有了這本書為主,再參考幾本翻譯的,如Bondy&Murty的"圖論及其應用",郵電出版社翻譯的"圖論和電路網路"等等,就馬馬虎虎,對本科生足夠了。
再進一步,世界圖書引進有GTM系列的Modern Graph Theory。此書確實經典!國內好像還有一家出版了個翻譯版。不過,學到這個層次,還是讀原版好。搞定這本書,也標誌著圖論入了門,呵呵。組合感覺沒有太適合的國產書。還是讀Graham和Knuth 等人合著的經典"具體數學"吧,有翻譯版,西電出的。
抽象代數,國內經典為莫宗堅先生的"代數學"。此書是北大數學系教材,深得好評。然而對本科生來說,此書未免太深。可以先學習一些其它的教材,然後再回頭來看"代數學"。國際上的經典可就多了,GTM系列裡就有一大堆。推薦一本談不上經典,但卻最簡單的,最容易學的:http://www.math.miami.edu/~ec/book/
這本Introduction to Linear and Abstract Algebra非常通俗易懂,而且把抽象代數和線性代數結合起來,對初學者來說非常理想。不過請注意版權問題,不要違反法律噢。
數論方面,國內有經典而且以困難著稱的"初等數論"(潘氏兄弟著,北大版)。再追溯一點,還有更加經典(可以算世界級)並且更加困難的"數論導引"(華羅庚先生的名著,科學版,九章書店重印)。把基礎的幾章搞定一個大概,對本科生來講足夠了。但這只是初等數論。本科畢業後要學計算數論,你必須看英文的書,如Bach的Introduction to Algorithmic Number Theory。理論計算機的根本,在於演算法。現在系裡給本科生開設演算法設計與分析,確實非常正確。環顧西方世界,大約沒有一個三流以上計算機系不把演算法作為必修的。
演算法教材目前公認以Corman等著的Introduction to Algorithms為最優。對入門而言,這一本已經足夠,不需要再參考其它書。南大曾翻譯出版此書,中文名為"現代計算機常用資料結構與演算法"。pie好像提供了網上課程的link,我也就不用廢話。
最後說說形式語言與自動機。我們用過北郵的教材,應該說寫的還清楚。但是,有一點要強調:形式語言和自動機的作用主要在作為計算模型,而不是用來做編譯。事實上,編譯前端已經是死領域,沒有任何open problem。如果為了這個,我們完全沒必要去學形式語言--用用yacc什麼的就完了。北郵的那本,在深度上,在跟可計算性的聯絡上都有較大的侷限,現代感也不足。所以建議有興趣的同學去讀英文書。不過英文書中好的也不多,而且國內似乎沒引進這方面的教材。
入門以後,把形式語言與自動機中定義的模型,和數理邏輯中用遞迴函式定義的模型比較一番,可以說非常有趣。現在才知道,什麼叫"宮室之美,百官之富"!
《胡侃學習計算機——理論之外》
如果計算機只有理論,那麼它不過是數學的一個分支,而不成為一門獨立的科學。事實上,在理論之外,電腦科學還有更廣闊的天空。我一直認為,4年根本不夠學習計算機的基礎知識,因為面太寬了。 一個一流計算機系的優秀學生決不該僅僅是一個程式設計高手,但他一定首先是一個程式設計高手。
我上大學的時候,第一門專業課時程式設計,現在好像改成了電腦科學導論?不管叫什麼名字,總之,念計算機的人就是靠程式吃飯。
去年在計算機系版有過一場爭論,關於第一程式設計語言該用哪一種。我個人認為,用哪種語言屬於末節,關鍵在養成良好的程式設計習慣。當年老師對我們說,打好基礎後學一門新語言只要一個星期。現在我覺得根本不用一個星期--前提是先把基礎打好。
資料結構有兩種不同的上法:一種把它當成降低要求的初級演算法課,另一種把它當成高階的程式設計課。現在國內的課程好像介乎兩者之間,而稍偏向前者。我個人認為,假如已經另有必修的演算法課,恐怕後一個目的更重要些。
國內流行的資料結構書也有兩種:北大的紅皮書(許卓群等著,高教版)和清華的綠皮書(嚴蔚敏等著,清華版)。兩書差距不大。紅皮書在理論上稍深一些,當然離嚴格的演算法書還差好遠。綠皮書更易接受些,而且佩有一本不錯的習題集,但我覺得它讓學生用虛擬碼寫作業恐怕不見得太好。最好還是把演算法都code以後debug一番,才能鍛鍊程式設計能力。
彙編預言和微機原理是兩門特煩人的課。你的數學/理論基礎再好,也佔不到什麼便宜。這兩門課之間的次序也好比先有雞還是先有蛋,無論你先學哪門,都會牽扯另一門課裡的東西。所以,只能靜下來慢慢琢磨。這就是典型的工程課,不需要太多的聰明和頓悟,卻需要水滴石穿的漸悟。
有關這兩門課的書,電腦書店裡不難找到。弄幾本最新的,對照著看吧。
類比電路這東東,如今不僅計算機系學生搞不定,電子系學生也多半害怕。如果你真想軟硬體通吃,那麼建議你先看看邱關源的"電路原理",也許此後再看類比電路底氣會足些。
教材:康華光的"電子技術基礎"還是不錯的。有興趣也可以參考童詩白的書。
數位電路比類比電路要好懂得多。閻石的書也算一本好教材,遺憾的一點是積體電路講少了些。真有興趣,到東南無線電系去旁聽他們的課。
計算機系統結構該怎麼教,國際上還在爭論。國內能找到的較好教材為Stallings的Computer Organization and Architecture: Designing for Performance(清華影印本)。國際上最流行的則是Computer architecture: a quantitative approach, by Patterson & Hennessy。
作業系統可以隨便選用Tanenbaum的Operating System Design and Implementation和Modern Operating System兩書之一。這兩部都可以算經典,唯一缺點 就是理論上不夠嚴格。不過這領域屬於Hardcore System, 所以在理論上馬虎一點也情有可原。
如果先把形式語言學好了,則編譯原理中的前端我看只要學四個演算法:最容易實現的遞迴下降;最好的自頂向下演算法LL(k);最好的自底向上演算法LR(k);LR(1)的簡化SLR(也許還有另一簡化LALR?)。後端完全屬於工程性質,自然又是another story。
推薦教材: Aho等人的著名的Dragon Book: Compilers: Principles, Techniques and Tools. 或者Appel的Modern Compiler Implementation in C.
學資料庫的第一意義是告訴你,會用VFP程式設計不等於懂資料庫。(這世界上自以為懂資料庫的人太多了!)資料庫設計既是科學又是藝術,資料庫實現則是典型的工程。
所以從某種意義上講,資料庫是最典型的一門計算機課--理工結合,互相滲透。
推薦教材:Silberschatz, et al., Database System Concepts.
網路的標準教材還是來自Tanenbaum: Computer Networks (清華影印本)。不過,網路也屬於Hardcore System,所以光看書是不夠的。建議多讀RFC,從IP的讀起。等到能掌握10種左右常用協議,就沒有幾個人敢小看你了。
必須結束這篇"胡侃"了,再侃下去非我力所能及。其實計算機還有很多基礎課都值得一侃,如程式設計語言原理,圖形影象處理,人工智慧等等。怎奈我造詣有限,不敢再讓內行恥笑。
最後宣告:前後的兩篇"胡侃"只針對本科階段的學習。即使把這些全弄通了,前面的路還長。
《理論電腦科學漫談》
電腦科學和數學的關係有點奇怪。二三十年以前,電腦科學基本上還是數學的一個分支。而現在,電腦科學擁有廣泛的研究領域和眾多的研究人員,在很多方面反過來推動數學發展,從某種意義上可以說是孩子長得比媽媽還高了。
但不管怎麼樣,這個孩子身上始終流著母親的血液。這血液是the mathematical underpinning of computer science(電腦科學的數學基礎)--也就是理論電腦科學。
現代電腦科學和數學的另一個交叉是計算數學/數值分析/科學計算,傳統上不包含在理論電腦科學以內。所以本文對計算數學全部予以忽略。
最常和理論電腦科學放在一起的一個詞是什麼?答:離散數學。這兩者的關係是如此密切,以至於它們在不少場合下成為同義詞。
傳統上,數學是以分析為中心的。數學系的同學要學習三四個學期的數學分析,然後是復變,實變,泛函等等。實變和泛函被很多人認為是現代數學的入門。在物理,化學,工程上應用的,也以分析為主。
隨著電腦科學的出現,一些以前不太受到重視的數學分支突然重要起來。人們發現,這些分支處理的數學物件與傳統的分析有明顯的區別:分析研究的物件是連續的,因而微分,積分成為基本的運算;而這些分支研究的物件是離散的,因而很少有機會進行此類的計算。人們從而稱這些分支為"離散數學"。"離散數學"的名字越來越響亮,最後導致以分析為中心的傳統數學分支被相對稱為"連續數學"。
離散數學經過幾十年發展,基本上穩定下來。一般認為,離散數學包含以下學科:
1) 集合論,數理邏輯與元數學。這是整個數學的基礎,也是電腦科學的基礎。
2) 圖論,演算法圖論;組合數學,組合演算法。電腦科學,尤其是理論電腦科學的核心是演算法,而大量的演算法建立在圖和組合的基礎上
3) 抽象代數。代數是無所不在的,本來在數學中就非常重要。在電腦科學中,人們驚訝地發現代數竟然有如此之多的應用。
但是,理論電腦科學僅僅就是在數學的上面加上"離散"的帽子這麼簡單嗎?一直到大約十幾年前,終於有一位大師告訴我們:不是。
D.E.Knuth(他有多偉大,我想不用我廢話了)在Stanford開設了一門全新的課程Concrete Mathematics。Concrete這個詞在這裡有兩層含義:
第一,針對abstract而言。Knuth認為,傳統數學研究的物件過於抽象,導致對具體的問題關心不夠。他抱怨說,在研究中他需要的數學往往並不存在,所以他只能自己去創造一些數學。為了直接面嚮應用的需要,他要提倡"具體"的數學。
在這裡我做一點簡單的解釋。例如在集合論中,數學家關心的都是最根本的問題--公理系統的各種性質之類。而一些具體集合的性質,各種常見集合,關係,對映都是什麼樣的,數學家覺得並不重要。然而,在電腦科學中應用的,恰恰就是這些具體的東西。Knuth能夠首先看到這一點,不愧為當世計算機第一人。
第二,Concrete是Continuous(連續)加上discrete (離散)。不管連續數學還是離散數學,都是有用的數學!
前面主要是從數學角度來看的。從計算機角度來看,理論電腦科學目前主要的研究領域包括:可計算性理論,演算法設計與複雜性分析,密碼學與資訊保安,分散式計算理論,平行計算理論,網路理論,生物資訊計算,計算幾何學,程式語言理論等等。這些領域互相交叉,而且新的課題在不斷提出,所以很難理出一個頭緒來。下面隨便舉一些例子。
由於應用需求的推動,密碼學現在成為研究的熱點。密碼學建立在數論(尤其是計算數論),代數,資訊理論,概率論和隨機過程的基礎上,有時也用到圖論和組合學等。
很多人以為密碼學就是加密解密,而加密就是用一個函式把資料打亂。這就大錯特錯了。現代密碼學至少包含以下層次的內容:
第一,密碼學的基礎。例如,分解一個大數真的很困難嗎?能否有一般的工具證明協議正確?
第二,密碼學的基本課題。例如,比以前更好的單向函式,簽名協議等。
第三,密碼學的高階問題。例如,零知識證明的長度,祕密分享的方法。
第四,密碼學的新應用。例如,數字現金,叛徒追蹤等。
在分散式系統中,也有很多重要的理論問題。例如,程序之間的同步,互斥協議。一個經典的結果是:在通訊通道不可靠時,沒有確定型演算法能實現程序間協同。所以,改進TCP三次握手幾乎沒有意義。例如時序問題。常用的一種序是因果序,但因果序直到不久前才有一個理論上的結果。例如,死鎖沒有實用的方法能完美地對付。
關於死鎖 --理論電腦科學漫談
我簡單地覺得與"熵"這個東西有關. 沒有這麼複雜。關鍵在效率:對付死鎖的方法,例如死鎖檢測,都非常嚴重地減低效率,以至於得不償失,因為死鎖並不是一種經常出現的現象。所以在全域性上,一般都用所謂"鴕鳥演算法",也就是假裝什麼都不會發生。在區域性上,例如你要設計一個訪問共享資料的演算法,那麼你就要證明你的演算法在區域性上是deadlock free。至於它會不會導致全域性的死鎖,就煩不了許多了。
《sir:關於<胡侃學習計算機>的一些補充說明》
大約兩年以前,我寫了《胡侃》一文並貼在本版,此後陸續有一些同學來信詢問相關的問題。為了完整起見,在此我把一些比較重要的想法補充如下。
(1)《胡侃》一文雖然覆蓋面僅限於計算機系的本科課程,但總體要求甚高。在寫作此文時,我的想法是更高的目標有利於激勵學習的熱情。因此,事實上本科生要在四年之內達到文中所說的水平,讀完所給的所有的參考書,幾乎沒有可能。如果你能學到六七成,就可以算非常優秀的學生,不必再拘泥於《胡侃》一文所指的方向。而如果你在學習時遇到有困難,也完全不必感到灰心喪氣。你遇到的困難,99.99%的人也同樣會遇到。問題不在於有沒有困難,而在於面對困難你能走多遠。
(2)坦率地說,《胡侃》一文中含有重大的偏見。因為我本人是從事理論研究的,所以我個人的想法不可避免地擡高了理論而貶低了電腦科學的其它分支。但就實際情況而言,並非所有的學生都會學習理論,甚至絕大部分學生的方向都不是理論。因此,每個人在學習時有必要根據自己的實際來取捨《胡侃》中提到的內容。據個例子講,如果你準備做作業系統,那麼集合論、數理邏輯對你來說幾乎沒有用處,完全可以捨棄;組合數學、圖論也只要最淺顯的一點就可以了;代數也一樣.....你需要的數學基礎可能會包括一點排隊論之類的東西。但更重要的,你需要大量的工程實踐,需要去研究linux核心,X-Windows.......需要去Hack各種常見的系統軟體,需要對作業系統的工作有一個global picture。由於這樣的工作並非我的長處,請不要期望能從《胡侃》一文中得到多少幫助。請記住,每個人的目光都有侷限,《胡侃》的作者只不過比你多學了幾年,成熟了的你很快會發現他的侷限。
(3)最理想的學習方法當然是從基礎出發,每一步都紮紮實實。但我國的傳統過分地強調了這一點。其實,由於種種原因,我們的研究生、高年級本科生常常並沒有把基礎課學得盡善盡美,甚至有很多必要的基礎課根本沒學過。那麼應該怎麼辦?從頭學起嗎?你有足夠的時間和精力從大一開始重學一遍嗎?這樣的熱情很好,可惜一般不符合實際。看看美國為代表的教學體系,你就會發現還有另外一種學法,那就是需要什麼的時候再補學什麼。實踐證明,美國的學生並不明顯比其它國家的學生差----或者說他們有自己的長處。如果你也是一個正在給自己“補課”的研究生,為什麼不能參照一下美國人的方法呢?