《面向算法設(shè)計的數(shù)據(jù)結(jié)構(gòu)》之前世今生

《面向算法設(shè)計的數(shù)據(jù)結(jié)構(gòu)(C++語言版)》

(上) 混沌篇

教材選用

2004年的春天, 我開始講授數(shù)據(jù)結(jié)構(gòu)這門課程. 雖然那會已經(jīng)不是第一次上講臺, 但講這門課時感覺完全是陌生的, 后來想想原因大概在于教材吧.

上學(xué)的時候用的是嚴(yán)蔚敏老師的《數(shù)據(jù)結(jié)構(gòu)》(綠皮Pascal版), 這本書流傳甚廣而且影響巨大(后期改了C語言版同樣熱銷). 由于在語言上的偏好, 我當(dāng)時想用C++版來講授這門課程, 所以選用了殷人昆老師的《數(shù)據(jù)結(jié)構(gòu)(用面向?qū)ο蠓椒ㄅcC++描述)》這本書. 事實上, 當(dāng)時C++代表了“先進”的生產(chǎn)力, 人們對它趨之若鶩. 另外, 殷老師的這本書在當(dāng)年還算比較新, 而且內(nèi)容嘗試很大膽, 不過里面有些疏漏給教學(xué)或多或少地帶來了不便(后來的第2版改進了很多).

說到這里, 不能不提Horowitz和Sahni的《數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)》這本書, 它給我的感覺就是講了很多內(nèi)容, 特別龐雜, 但似乎不能讓讀者明白真義所在. 在Horowitz和Sahni寫作的年代, 數(shù)據(jù)結(jié)構(gòu)的研究只能算是剛起步, 還沒有系統(tǒng)性地整理并用于教學(xué), 所以會有東一榔頭西一棒的感覺. 其實, 核心的問題是: 我們這門課程究竟應(yīng)該學(xué)哪些內(nèi)容? 但是, 在那個年代沒有辦法交代地特別清楚.

有人會問, 為什么不選外版教材呢? 一方面當(dāng)時的環(huán)境還不太普及, 例如《算法導(dǎo)論》的影印版2002年才正式引入國內(nèi), 而且引進的優(yōu)秀外版教材不是特別多.[1] 另一方面就是學(xué)生還是喜歡中文教材, 這一點至今如是. 所以, 發(fā)展本版教材是非常重要的.

開發(fā)環(huán)境

2004年那會在學(xué)校用的比較多的還是Visual C++ 6.0, 里面的坑不少, 對C++98的標(biāo)準(zhǔn)支持也不是很理想. 現(xiàn)在一晃而過, 出了很多新鮮的工具, 比如Clang. 而且現(xiàn)在連Visual Studio 2017都發(fā)布了.

不過, 說實話那個年代的STL確實不太成熟, 換gcc也好不到哪里去. 而且考慮到學(xué)生的實際情況, 還是微軟系列的相對比較方便一些. 現(xiàn)在我會要求學(xué)生在筆記本上安裝Visual Studio 2015的社區(qū)版, 如果電腦配置不行的話, 可以換一個比較低的版本例如Visual Studio 2013. 這樣可以方便地支持C++11, 不過回想當(dāng)年真是困難重重.

學(xué)習(xí)筆記

值得欣慰的是, 當(dāng)年的學(xué)生很有韌性, 非常認(rèn)真地在學(xué)習(xí)這門課程. 據(jù)說某位認(rèn)真聽課的同學(xué)把我講的話全部記錄下來了, 整整寫滿了三個大筆記本. 其實我特別好奇這位同學(xué)都記了些什么, 現(xiàn)在要是能看看, 也許能回憶起不少過去的時光.

說到這里, 我想額外多說幾句. 記筆記無論是手寫茬底、iPad/Surface Pro記錄抑或是LaTeX錄入(前提要有一定的手速, 而且要求對LaTeX比較熟練), 都是不錯的. 因為在記筆記的過程中是一種頭腦的讀入, 這可比手機拍下來要強多了. 許多人覺得拍下來就是自己掌握了, 其實很可能永遠(yuǎn)躺在手機相冊里再也不看了.

STL

非常幸運地是, 清華大學(xué)出版社當(dāng)時影印并且翻譯了Ford和Topp的那本《數(shù)據(jù)結(jié)構(gòu)——C++語言描述:應(yīng)用標(biāo)準(zhǔn)模板庫(STL)》. 這本書所指引的思路非常正確, 就是一開始從STL入手學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu), 并且充分利用已經(jīng)有的結(jié)果來搭建一個比較的程序. 然后我們再去學(xué)習(xí)新的知識, 比如STL的內(nèi)部構(gòu)造. 這樣的方案在STL不是很成熟的時候確實有很大的風(fēng)險, 比如那時候的STL沒有將散列納入標(biāo)準(zhǔn), 所以只能用Plauger實現(xiàn)的hash_map. 事實上, 那個時代的C++也不是很成熟, 為了求證一個問題, 我專門給C++ Primer的作者Lippman發(fā)了郵件, 他坦承那是編譯器尚不支持的功能.

Ford和Topp的這本書很厚, 直接用于教學(xué)不太方便. 為了讓同學(xué)們能夠充分吸取其中的思想, 我編寫了一本名為《算法與數(shù)據(jù)結(jié)構(gòu)補充教材》的小冊子, 專門講解STL中各種容器的基本使用方案. 這本小冊子大概只有60多頁, 但是足夠大家使用了. 現(xiàn)在回過頭來看, Ford和Topp的這本書里面有很多不甚專業(yè)的地方, 有些講解也不夠嚴(yán)謹(jǐn), 但它確實是一本還算不錯的書.

備課講義

從備課的角度看, 第一次在筆記本上手寫講義比較合適. 人在思考的時候用手寫筆記會比較適應(yīng), 也能夠全身心投入問題的本質(zhì)而不是去考慮錄入公式之類的問題. 但講完第一次之后我發(fā)現(xiàn)了這種模式的問題——后續(xù)的修改非常麻煩. 于是第二次上課的時候我就開始全面投向電子講義, 不過用的是Word來記錄, 這也是一個非常大的坑(主要是它太“智能”了).

電子講義的好處就是可以無限提升和改進, 這點非常方便. 但是在修改的過程中逐漸發(fā)現(xiàn)Word的各種不便, 而且公式也不是很好看, 于是我開始投向LaTeX的懷抱. 說起來很多美國大學(xué)讓學(xué)生入學(xué)的時候就使用LaTeX來提交筆記和作業(yè), 這點我現(xiàn)在非常贊同. 因為對于學(xué)術(shù)寫作來說, LaTeX是必須掌握的技能點. 由于條件所限, 我不能強制要求現(xiàn)在學(xué)生都使用它, 但希望大家特別是還在上學(xué)的同學(xué)們都去學(xué)習(xí)和掌握LaTeX. 雖然學(xué)習(xí)曲線有點陡峭, 但是你會發(fā)現(xiàn)漂亮的排版會激發(fā)你繼續(xù)前行.

我現(xiàn)在上課會用一款Typora的軟件, 完美支持MarkDown和LaTeX公式. 很多公式利用它能夠快速展現(xiàn)在屏幕上, 而且可以保留下來放到下一次課程繼續(xù)改進. 想像一下, 鍵入幾個符號就能出現(xiàn)清晰的數(shù)學(xué)公式, 比在黑板上手寫公式要方便多了(不過需要苦練LaTeX和手速). 如果有興趣的朋友, 不妨試試這款軟件, 效果無比驚艷......

故事開始

說了很多廢話, 這篇卻要結(jié)束了. 實際上, 正是《算法與數(shù)據(jù)結(jié)構(gòu)補充教材》和這些不斷改善的講義, 才揭開了《面向算法設(shè)計的數(shù)據(jù)結(jié)構(gòu)(C++語言版)》的漫漫征程......

(中) 頓悟篇

綱舉目張

很多年前流傳著一本叫《現(xiàn)代計算機常用數(shù)據(jù)結(jié)構(gòu)和算法》的黑皮書, 譯者是南京大學(xué)的潘金貴老師等人. 雖然由于時代所限, 導(dǎo)致這本書沒有版權(quán), 但起到了傳播交流的巨大貢獻. 后來大家知道了, 這就是傳說中的《算法導(dǎo)論》啊! 從譯名可以看出, 我們的認(rèn)知停留在數(shù)據(jù)結(jié)構(gòu)與算法這個層面. 很多人不明白, 這本《算法導(dǎo)論》里面為什么書名不體現(xiàn)數(shù)據(jù)結(jié)構(gòu)但又講很多數(shù)據(jù)結(jié)構(gòu)呢? 這種組織似乎非常讓人不解.

我個人認(rèn)為, 《算法導(dǎo)論》中對數(shù)據(jù)結(jié)構(gòu)中的態(tài)度非常明確, 作者的思路就是: 數(shù)據(jù)結(jié)構(gòu)要服務(wù)于算法, 否則就是屠龍之術(shù), 應(yīng)該摒棄. 例如圖算法它只給出常用的鄰接矩陣和鄰接表, 那些各種應(yīng)該退出歷史舞臺的結(jié)構(gòu)完全不講. 這樣一來, 整個思路就非常明晰了.

集合

那么如何將這些跨入到數(shù)據(jù)結(jié)構(gòu)課程呢. 關(guān)鍵點在于抽象數(shù)據(jù)類型, 而最關(guān)鍵的一點就是集合這個抽象數(shù)據(jù)類型, 它包含如下操作:

  • 查找. 在集合中查找元素k.
  • 插入. 在集合中插入元素k.
  • 刪除. 在集合中插入元素k.
  • 最小元. 返回集合的最小元素.
  • 最大元. 返回集合的最大元素.
  • 下一元素. 返回比k大的最小元素.
  • 上一元素. 返回比k小的最大元素.

通過這些操作我們可以構(gòu)造出許多完整的程序, 而不同的程序需要不同的側(cè)重點, 例如側(cè)重于查找的集合或側(cè)重于最大元的集合. 《算法導(dǎo)論》對此表述地很明確, 專門放在數(shù)據(jù)結(jié)構(gòu)部分的引言部分, 開宗明義地闡述了作者的思想.

種類

更具體的教學(xué)內(nèi)容到底應(yīng)該是哪些呢? Robert E. Tarjan在其名作《數(shù)據(jù)結(jié)構(gòu)與網(wǎng)絡(luò)算法》(Data structures and network algorithms)中給出了非常精辟的總結(jié):

  1. 區(qū)間: 包括數(shù)組/向量, 其特點是以O(1)時間訪問元素. 注意區(qū)間的下標(biāo)可以雙向延伸, 也即這里可能存在負(fù)數(shù)下標(biāo).
  2. 列表: 包含鏈辫愉、棧和隊列. 這三種看似簡單的抽象數(shù)據(jù)類型在圖算法中的應(yīng)用可謂是精彩紛呈.
  3. 集合: 不一定有序關(guān)系, 以查找為主, 可用散列實現(xiàn). 《算法導(dǎo)論》上稱此為字典.
  4. 映射: 定義于全序集, 有最小和最大元素, 可用查找樹實現(xiàn). 此外映射還可引出優(yōu)先級隊列.

另外安利一下, Tarjan這位算法大宗師的書雖然薄薄一本, 但實在是微言大義, 值得深入閱讀.

書名之疑

另外有一本書也對我起到了比較深遠(yuǎn)的影響, 那就是Weiss的《數(shù)據(jù)結(jié)構(gòu)與算法分析》(Data Structures and Algorithm Analysis), 可能有些人對這本書的名字感到困惑, 為什么數(shù)據(jù)結(jié)構(gòu)要和算法分析掛鉤呢?

實際上, 作者的用意就是數(shù)據(jù)結(jié)構(gòu)必須以算法分析為導(dǎo)向. 我們選擇一種數(shù)據(jù)結(jié)構(gòu), 最關(guān)鍵的是看能否滿足整個程序的需求, 而其中的準(zhǔn)則就是算法分析結(jié)果. 是好是壞, 都由算法分析說了算, 這點撐起了整本書的結(jié)構(gòu). 事實上, Weiss的這一系列書有多個語言版本, 一直都是熱銷的教材. 我想, 這和作者的整體思路有很大的關(guān)系.

想了很久, 最終給自己的書定名為《面向算法設(shè)計的數(shù)據(jù)結(jié)構(gòu)》.

寫作思路

有了上述幾座燈塔的指引, 我也逐漸為自己的講義定出了方向:

基于抽象數(shù)據(jù)類型的觀點講解數(shù)據(jù)結(jié)構(gòu), 以算法分析為導(dǎo)向, 以算法效率為準(zhǔn)繩, 著墨于抽象數(shù)據(jù)類型的選擇悟狱、使用和組合, 從而實現(xiàn)提升算法性能的終極目標(biāo).

落到實處就是將STL的使用作為首位, 盡量與C++11標(biāo)準(zhǔn)靠攏, 提倡拿來主義少造輪子, 力爭快速構(gòu)建可用程序.

在草稿逐漸積累的時候, 清華大學(xué)出版社的龍啟銘先生和我商談了這本書的出版事宜. 雖然非常迅速地完成了簽約工作, 不過由于我的拖延癥和一些事情, 遲遲未能交稿. 這時候, 啟銘兄經(jīng)常激勵和鞭策我, 讓我最終將這本書呈現(xiàn)在大家面前.

另外, 由于我的完美主義傾向, 總想把書修訂地非常完善. 后來發(fā)現(xiàn)這是一個不可能完成的任務(wù), 與其這樣還不如在一定階段推出一個版本, 今后再逐漸迭代更新. 事實證明, 這樣做非常明智.

(下) 進化篇

《面向算法設(shè)計的數(shù)據(jù)結(jié)構(gòu)(C++語言版)》自從2015年12月出版以來, 得到了很多非常有益的反饋, 這為下一版的改進提供了很好的思路. 特別是2016年我開了微博(現(xiàn)在更名為@算法時空)之后, 在與各界人士互相交流的過程中, 更是發(fā)現(xiàn)了這本書的種種不足.

libc++

目前標(biāo)準(zhǔn)庫實現(xiàn)中邏輯性和可讀性最好的當(dāng)屬LLVM的libc++, 當(dāng)然大家也都知道Clang, 具體它們的關(guān)系我也不細(xì)說了. 本書下一版將考慮講解一些libc++的實現(xiàn), 讓大家可以多接觸到這種業(yè)界頂級的源代碼.

更多容器

由于寫作時間所限, 第1版里沒有講到一大類容器, 也就是unordered系列(unordered_set, unordered_map, unordered_multiset, unordered_multimap). 這也是本書的一大遺憾, 我們在第2版將介紹這些容器. 實際上, 它們的平均表現(xiàn)很好, 但也有可能在最壞情況下極差. 讀者一定不要只看它們的優(yōu)點, 也要多甄別選用.

代碼優(yōu)化

下一版會引入更多優(yōu)化實例, 比如在遞歸中會講解qsort函數(shù), 它對于遞歸的優(yōu)化相當(dāng)好, 非常值得一讀. 更重要的是, 我們將會在書中更強調(diào)STL的使用而不是自己編寫函數(shù), 盡可能像樂高積木一樣用STL搭建出復(fù)雜的系統(tǒng), 這樣性能更好也更簡潔.

極限性能

我們將會展示更多極限情況下的性能, 而不是一些非常簡單的例子. 比如, 可以讓讀者嘗試將自己的內(nèi)存用量壓榨到極致, 看看會有什么變化. 而這些鮮活的實例正是教學(xué)所需要的, 也是學(xué)習(xí)者所感興趣的話題. 實際上, 這有點數(shù)據(jù)庫壓力測試的意思, 從這里我們也可以看到并且驚嘆于STL的抗壓能力.

算法應(yīng)用

我們考慮展示更多數(shù)據(jù)結(jié)構(gòu)在算法中的應(yīng)用, 特別是引入高效數(shù)據(jù)結(jié)構(gòu)之后算法性能發(fā)生顯著變化的實例. 只有通過這些實實在在的例子, 才能讓學(xué)習(xí)者感受到數(shù)據(jù)結(jié)構(gòu)之妙. 事實上, 寫作本書的目的也是為了配合后續(xù)進階算法課程的需要, 希望能讓這本書成為學(xué)習(xí)《算法導(dǎo)論》和《算法設(shè)計》的一個良好鋪墊, 能讓大家順利學(xué)好更深入的算法設(shè)計的技術(shù).

建議

歡迎讀過本書的朋友們在本篇文章下寫留言, 寫出你們的意見和建議. 我會在第2版中加以改進和完善.


  1. 不過順便八卦一下, 如果你手里有《算法導(dǎo)論》影印版的話, 可以看到封底有個“線性編程”一直沒改為正確的“線性規(guī)劃”. ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗤谚,一起剝皮案震驚了整個濱河市舆床,隨后出現(xiàn)的幾起案子缕粹,更是在濱河造成了極大的恐慌登夫,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驻民,死亡現(xiàn)場離奇詭異翻具,居然都是意外死亡履怯,警方通過查閱死者的電腦和手機回还,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叹洲,“玉大人柠硕,你說我怎么就攤上這事≡颂幔” “怎么了蝗柔?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長民泵。 經(jīng)常有香客問我癣丧,道長,這世上最難降的妖魔是什么栈妆? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任胁编,我火速辦了婚禮厢钧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嬉橙。我一直安慰自己早直,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布市框。 她就那樣靜靜地躺著霞扬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枫振。 梳的紋絲不亂的頭發(fā)上喻圃,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音粪滤,去河邊找鬼级及。 笑死,一個胖子當(dāng)著我的面吹牛额衙,可吹牛的內(nèi)容都是我干的饮焦。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼窍侧,長吁一口氣:“原來是場噩夢啊……” “哼县踢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伟件,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤硼啤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后斧账,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谴返,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年咧织,在試婚紗的時候發(fā)現(xiàn)自己被綠了嗓袱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡习绢,死狀恐怖渠抹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闪萄,我是刑警寧澤梧却,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站败去,受9級特大地震影響放航,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜圆裕,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一广鳍、第九天 我趴在偏房一處隱蔽的房頂上張望缺菌。 院中可真熱鬧,春花似錦搜锰、人聲如沸伴郁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焊傅。三九已至,卻和暖如春狈涮,著一層夾襖步出監(jiān)牢的瞬間狐胎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工歌馍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留握巢,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓松却,卻偏偏與公主長得像暴浦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子晓锻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容