編程珠璣,字字珠璣

無論你自稱是“程序猿”還是“攻城師”,只要在寫程序,都免不了要和算法打交道。說起算法,第一本從你的記憶中檢索出的圖書是什麼呢?是經典的大部頭《算法導論》?還是之前大紅大紫的《編程之美》?以前它們幾乎是同時映入我腦海的,分不清誰先誰後,這兩本書我都讀過,前者是在學校的算法課上,而後者則是在畢業求職前。

最近,我終於有了一個明確的答案,在這些算法相關的書籍中,最讓我愛不釋手的是《編程珠璣》這本薄薄的小冊子,因爲它真正激發起了我對學習算法的熱情。不愧是培養了James Gosling(Java之父)、Charles Leiserson(《算法導論》作者)等衆多大師的“超級大師”的傳世之作。與學校裏接觸的“教材式”的書不同,《編程珠璣》更像是“問答式”的,拋出一個由實際問題簡化而來的問題,然後一步步進行分析解答,作者將想要傳達給讀者的知識與技巧貫穿其中,期間還經常讓人發自內心地感嘆一下,原來還能這麼做。

以書中第8章爲例,我把問題簡單描述爲“輸入一個長度爲n的數組x,求其中任意連續子元素相加的最大和”。最常規的思路就是寫一個三層嵌套的循環,算法的執行時間爲O(n3),時間似乎有點長,做點優化,充分利用之前的計算結果,可以節省一層循環,於是得出了一個O(n2)的算法。如果引入“分治”的思路,將數組拆開,分別求解,然後再合併起來,這樣只需O(nlogn)的時間。別以爲這樣就結束了,終極方案總是出現在最後的,直接從頭開始掃描數組,一次掃描得出結果(具體算法請允許我賣個關子),O(n)時間內就能解決問題,神奇吧。千萬不要以爲這是專門用來教授算法知識的假想的“教學問題”,這可是源自布朗大學的Ulf Grenander曾經遇到過的真實問題,可見設計一個好的算法是多麼重要。

在日常工作中,估計大多數人都不太有機會遇到太複雜的算法,就算遇到了,也可以僥倖依靠強大的計算和存儲能力來解決問題。誠然現在的服務器計算能力越來越強,1個內核可以抵得上從前的幾個龐然大物,更何況CPU還是多核的,內存都按GB計算,但不能因爲這樣就認爲現在算法和數據結構的重要性不如從前了。假設上文提到的問題中不是計算數組元素,而是每次循環需要操作數據庫或者調用遠程服務,一次操作就要耗時幾毫秒,甚至是幾百毫秒,那麼O(n3)和O(n)的區別就顯而易見了。加服務器不是唯一的解決方案,有時簡單地調整算法能讓你省下大把的金錢和時間。

再來說說空間的問題,節省空間似乎已經不再重要了,對某些人來說是這樣,但不可否認還是存在很多場景,需要錙銖必較,仔細地設計算法和數據結構。嵌入式設備就不說了,來說說眼下流行的Redis,爲了能最大限度地使用好服務器的內存空間,減少浪費,antirez在編寫Redis時就煞費苦心地改良數據結構,真的是能省1字節算1字節。HDFS和BigTable面向海量存儲,照理說它們都是不缺空間的主,可是其中還是提供了LZO、Snappy等衆多壓縮算法,用“閒置”的CPU運算時間來換取更多的空間……類似的例子還有很多,所以在編寫代碼時,如果條件允許,請再多考慮一下自己的實現。

多數Java程序員應該都有GC調優的經歷,遇到GC過於頻繁,耗時太長的情況,通常會對JVM的堆配置做調整,如果調整的效果都不明顯呢?來看看代碼吧,也許對代碼稍作修改,優化下算法,就能把陡峭的內存增長曲線將下來了。啊哈,算法!

書中還時不時地回顧下歷史,比如二分搜索,相信大多數人都知道是怎麼回事,可是你知道麼,第一篇二分搜索的論文1946年就發表了,可是直到1962年纔有人寫出了第一個完全正確的二分搜索程序,太讓人驚訝了,這個可是如今算法教材上的標配啊。還有那些在編碼規範中經常出現的最長不要超過80個字符,其中80的由來原來和早期的打孔卡有關(如果對這個話題感興趣,可以閱讀阮一峯的這篇文章)。

薄薄的《編程珠璣》,兩百多頁捧在手上完全沒有板磚的壓力,可以將其作爲教材以外的輔助讀物,工具書以外的休閒讀物,亦或者是和我一樣,將其作爲睡前讀物,每晚睡前讀上幾頁,和算法聊上幾句,和數據結構打個招呼。

 

P.S.之前一篇文章說了要把一些自己原創發表在InfoQ上的內容放到自己的博客裏,這就是第一篇

[首發於InfoQ中文站:http://www.infoq.com/cn/news/2011/11/programming-pearls ]


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章