數(shù)據(jù)結(jié)構(gòu)與算法
定 價:69.5 元
當前圖書已被 1 所學校薦購過!
查看明細
- 作者:郭煒
- 出版時間:2025/8/1
- ISBN:9787302696360
- 出 版 社:清華大學出版社
- 中圖法分類:TP311.12
- 頁碼:
- 紙張:膠版紙
- 版次:
- 開本:16開
本書內(nèi)容全面、細致、通俗易懂。涵蓋線性表、棧和隊列、樹和二叉樹、堆、哈夫曼樹、并查集、AVL樹、紅黑樹、B樹和B+樹、串、圖、散列表等數(shù)據(jù)結(jié)構(gòu),以及枚舉、二分、遞歸、分治、動態(tài)規(guī)劃、貪心、深搜、廣搜、最短路、最小生成樹、拓撲排序、關(guān)鍵路徑、內(nèi)外排序等算法。對各類數(shù)據(jù)結(jié)構(gòu)和算法,不但要掌握理論,還應(yīng)熟練地編程實現(xiàn)。本書的最大特點是高標準的實踐性。除了少數(shù)幾個特別復(fù)雜的數(shù)據(jù)結(jié)構(gòu),95%的數(shù)據(jù)結(jié)構(gòu)和算法都給出了完整可運行的代碼,一共130多份,并且這些代碼幾乎都出現(xiàn)在具體的例題中。本書的例題和編程習題,都可以在北京大學在線程序評測平臺OpenJudge上提交解題程序并自動評判對錯。本書內(nèi)容和習題按難度做了明確分級,因此不論是高等學校計算機專業(yè)還是非計算機專業(yè)的師生,都可以從中各取所需用于教學。本書既可以用作數(shù)據(jù)結(jié)構(gòu)和算法入門教材,又可以作為考研、找工作面試的提高秘籍,還可以用于程序設(shè)計競賽的基礎(chǔ)培訓。
市場上講述數(shù)據(jù)結(jié)構(gòu)的書較多,但兼顧算法的不算多。本教材深度廣度相對都更大些。大多數(shù)數(shù)據(jù)結(jié)構(gòu)和算法教材采用偽代碼描述數(shù)據(jù)結(jié)構(gòu)和算法,實踐性稍弱。給出了絕大多數(shù)數(shù)據(jù)結(jié)構(gòu)和算法的完整可運行的C++程序,而且C++程序采用C++17標準,充分體現(xiàn)C++語言在實現(xiàn)數(shù)據(jù)結(jié)構(gòu)和算法方面的優(yōu)勢。本教材結(jié)合了在線程序評測平臺,例題習題都可以在平臺上提交,有很強的實踐性,符合目前考研和應(yīng)聘大多需要在在線評測平臺上編程做題的需求。大多數(shù)計算機專業(yè)的數(shù)據(jù)結(jié)構(gòu)課程教學,采用的是C語言。C語言不具備面向?qū)ο蟆⒎盒秃秃瘮?shù)式的特點,其實并不適合用來描述數(shù)據(jù)結(jié)構(gòu)和算法。因此計算機專業(yè)的數(shù)據(jù)結(jié)構(gòu)和算法課程教學,存在用C++語言替代C語言的改革需求。然而,C++語言學習較高的學習門檻,成為數(shù)據(jù)結(jié)構(gòu)和算法教學改革的障礙。本書精心挑選C++語言的核心內(nèi)容,去除編寫小型程序并不需要的特性,設(shè)計了適合4個課時課堂教學的“C++語言快速入門”章節(jié),使得掌握C語言的學生迅速可以掌握C++語言的核心,看懂用C++語言實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)和算法,并能模仿編寫,從而為從C語言轉(zhuǎn)變到C++語言的數(shù)據(jù)結(jié)構(gòu)和算法教學改革掃清了障礙。
前言
要成為的程序員,必須學習“數(shù)據(jù)結(jié)構(gòu)與算法”課程。雖然同類課程或教材有些只是名為“數(shù)據(jù)結(jié)構(gòu)”,沒有提到“算法”,但實際上,數(shù)據(jù)結(jié)構(gòu)和算法,沒有必要也無法嚴格區(qū)分,兩者是“你中有我、我中有你”的關(guān)系。或者,將數(shù)據(jù)結(jié)構(gòu)算作算法的一個分支也未嘗不可,如著名教材《算法導(dǎo)論》,其中就包含大量數(shù)據(jù)結(jié)構(gòu)的內(nèi)容。本書中涉及的問題,如果需要將數(shù)據(jù)以復(fù)雜的方式組織起來,就歸類為數(shù)據(jù)結(jié)構(gòu);否則,就歸類為算法。
大多數(shù)課程或教材,用C語言實現(xiàn)數(shù)據(jù)結(jié)構(gòu)和算法。然而,相比C++語言,甚至Java和Python語言,用C語言實現(xiàn)數(shù)據(jù)結(jié)構(gòu)和算法有明顯的劣勢。C語言沒有對面向?qū)ο蟪绦蛟O(shè)計方法的支持,實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)無法做到“封裝”和“隱藏”。不支持“封裝”,導(dǎo)致代碼缺乏局部性,難以理解,難以維護。不支持“隱藏”,導(dǎo)致無法防止數(shù)據(jù)結(jié)構(gòu)從外部被不慎破壞,缺乏安全性。C語言不支持泛型程序設(shè)計,導(dǎo)致實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)和算法缺乏通用性或可重用性。例如,編寫一個可以對任何數(shù)據(jù)類型的數(shù)組排序的函數(shù)、編寫一個可以存放任何數(shù)據(jù)類型的二叉查找樹數(shù)據(jù)結(jié)構(gòu)是比較困難的,即便實現(xiàn)了,這樣的函數(shù)和數(shù)據(jù)結(jié)構(gòu)的使用方式也較為麻煩和不自然。C語言無可變長數(shù)組,這導(dǎo)致在實現(xiàn)圖的鄰接表、樹等數(shù)據(jù)結(jié)構(gòu)時不得不采用鏈表、兒子兄弟樹等編程效率或運行效率不佳的方案?傊皵(shù)據(jù)結(jié)構(gòu)與算法”是理論結(jié)合實踐的課程,對數(shù)據(jù)結(jié)構(gòu)和算法的編程實現(xiàn),不但應(yīng)該正確,還應(yīng)在工程上是優(yōu)美的,即安全、簡潔、好用、可重用,這用C語言很難做到。目前,程序設(shè)計方法的潮流是面向?qū)ο、泛型和函?shù)式編程,C語言對這三大特性均無支持,故作者認為,當前的數(shù)據(jù)結(jié)構(gòu)和算法教學,亟須改革,將用C語言描述數(shù)據(jù)結(jié)構(gòu)和算法,轉(zhuǎn)變?yōu)橛弥С置嫦驅(qū)ο、支持泛型和函?shù)式編程的C++語言描述。
然而,系統(tǒng)掌握C++語言有較高的學習成本,即便對已經(jīng)掌握C語言的編程者也是如此,這是阻礙C++語言在數(shù)據(jù)結(jié)構(gòu)和算法教學中得以推廣的主要原因。實際上,C++語言的大量特性,如異常處理、繼承、多態(tài)等,是為了編寫大型程序而設(shè)計的,數(shù)十行或一百多行代碼即可實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)和算法不需要使用這些特性,因而用C++語言進行數(shù)據(jù)結(jié)構(gòu)與算法教學,其實無須學員系統(tǒng)地掌握C++語言,只須學會C++語言中一小部分最核心的面向?qū)ο蟆⒎盒秃秃瘮?shù)式編程特性即可。為此,作者抽取了這部分核心特性,精心編寫了“C++語言快速入門和溫故知新”一章,依此章進行4個課時的教學,可使學過C語言的學生掌握C++語言的精髓,從而可以充分理解本書的所有程序,并用C++語言編寫小型程序。本書完全適用于只學過C語言的讀者,故雖然所有程序均用C++語言實現(xiàn),卻依然命名為《數(shù)據(jù)結(jié)構(gòu)與算法(C/C++語言實現(xiàn))》。
作者在北京大學講授“數(shù)據(jù)結(jié)構(gòu)與算法”和“數(shù)據(jù)結(jié)構(gòu)與算法實習”課程多年,并曾擔任北京大學ACM國際大學生程序設(shè)計競賽隊教練9年。作者講授的這些課程,既有面向非計算機專業(yè)的,也有面向計算機專業(yè)的。本書即是對這些課程教學經(jīng)驗的歸納與整合。
本書數(shù)據(jù)結(jié)構(gòu)部分包括線性表、棧、隊列、二叉樹、堆、哈夫曼樹、樹和森林、并查集、散列表、二叉查找樹、AVL樹、紅黑樹、B樹、B+樹、圖、矩陣等內(nèi)容。算法部分包括枚舉、二分、遞歸、深度優(yōu)先搜索、廣度優(yōu)先搜索、貪心、動態(tài)規(guī)劃、內(nèi)排序、外排序、最短路、最小生成樹、拓撲排序、關(guān)鍵路徑等內(nèi)容。數(shù)據(jù)結(jié)構(gòu)部分和算法部分交替講述。本書內(nèi)容覆蓋計算機專業(yè)408考研大綱。
相比大部分同類教材,本書的知識覆蓋面更廣,尤其是算法部分。
閱讀本書需要讀者已經(jīng)掌握C語言程序設(shè)計的基礎(chǔ)知識。對于學過C語言程序設(shè)計的讀者,本書非常適合作為第二門編程課的教材。
本書內(nèi)容和習題按難度明確分級,不論是高校計算機專業(yè)還是非計算機專業(yè)的師生,都可以從中各取所需。不帶“★”標記的是基本內(nèi)容,適用于所有讀者;計算機專業(yè)的讀者應(yīng)掌握帶“★”標記的章節(jié);標記為“★★”的內(nèi)容,則適用于高水平院校計算機專業(yè)的教學;少數(shù)標記為“★★★”的例題和習題,難度與大學生程序設(shè)計競賽的中等題相當。有些例題習題來自早年的程序設(shè)計競賽,或在競賽中本就是簡單題,難度不高,因而沒有“★★★”標記,甚至沒有“★”標記。
作者考察了許多國內(nèi)外流行的數(shù)據(jù)結(jié)構(gòu)與算法教材,發(fā)現(xiàn)許多教材中多用偽代碼,或不完整的代碼來描述數(shù)據(jù)結(jié)構(gòu)和算法,很少給出能直接運行的完整程序。不但需要實打?qū)嵕幊探鉀Q的例題很少,而且配套的習題,基本都是考查概念,或只要求描述解決問題的過程,幾乎不會要求寫出完整的、完全正確的程序。即便一些教材中有編程習題,讀者也無法評判自己編寫的解題程序是否完全正確無隱錯。用這樣的教材教學,雖然可以應(yīng)付考研等筆試考試,但是難免有紙上談兵之嫌。一旦碰到企業(yè)招聘要求現(xiàn)場寫代碼,或者考研復(fù)試要求上機寫代碼,往往力不從心。
相比大多數(shù)數(shù)據(jù)結(jié)構(gòu)和算法教材,本書的最大特點就是高標準的實踐性。除了少數(shù)幾個特別復(fù)雜的數(shù)據(jù)結(jié)構(gòu),95%的數(shù)據(jù)結(jié)構(gòu)和算法都給出了完整可運行的代碼,并且這些代碼大部分都出現(xiàn)在具體的例題中。
本書的例題和編程習題,都可以在北京大學在線程序評測平臺OpenJudge上提交解題程序。平臺廣泛用于北京大學“計算概論”“程序設(shè)計實習”“數(shù)據(jù)結(jié)構(gòu)與算法”等編程類課程的教學。要在OpenJudge上完成本書的編程習題,必須對相應(yīng)的數(shù)據(jù)結(jié)構(gòu)和算法知識的每個實現(xiàn)細節(jié)都清楚地掌握,且編寫的程序不能有隱錯,這樣的要求,比自己寫個程序隨意測試一下沒發(fā)現(xiàn)問題就算對了要高得多,更遠非在紙上寫寫畫畫的筆試型習題可比。OpenJudge的具體使用方法見附錄。
本書配套電子資料齊全,包括課程講義以及130多個風格簡潔優(yōu)美的程序源碼。
本書還另有Python語言版和Java語言版,均已經(jīng)由清華大學出版社出版。
作者水平有限,書中難免存在一些不足及疏漏之處,懇請讀者批評指正。讀者可以通過guo_wei@pku.edu.cn與作者溝通、交流。
作者的女兒兼校友郭小美審閱并校對了全部書稿。一部分程序由她從作者編寫的其他語言的程序改寫為C++程序,特此感謝。
郭煒
于北京大學信息科學技術(shù)學院
2025年4月
郭煒,北京大學信息科學技術(shù)學院教師。曾擔任北京大學ACM大學生程序設(shè)計競賽隊教練9年。在中國大學MOOC獨立開設(shè)的《程序設(shè)計與算法》系列課程獲評國家精品在線開放課程。在華文慕課和另一教師合開的《程序設(shè)計實習》獲評國家精品在線開放課程。編著有《新標準C++程序設(shè)計》、《Python程序設(shè)計基礎(chǔ)及實踐(慕課版)》、《新標準C++程序設(shè)計》、《Python程序設(shè)計基礎(chǔ)及實踐(慕課版)》、《算法基礎(chǔ)與在線實踐》、《ACM國際大學生程序設(shè)計競賽亞洲區(qū)預(yù)選賽真題題解》等教材。
目錄
第1章緒論1
1.1算法和算法分析1
1.1.1什么是算法1
1.1.2算法的時間復(fù)雜度及其表示法3
1.2數(shù)據(jù)結(jié)構(gòu)7
1.2.1數(shù)據(jù)的邏輯結(jié)構(gòu)7
1.2.2數(shù)據(jù)的存儲結(jié)構(gòu)7
1.2.3數(shù)據(jù)結(jié)構(gòu)上的操作8
小結(jié)8
習題9
第2章C++語言快速入門和溫故知新10
2.1從C到C++10
2.1.1文件名和頭文件10
2.1.2輸入/輸出11
2.1.3結(jié)構(gòu)體名直接作為類型名12
2.1.4引用12
2.1.5const關(guān)鍵字13
2.1.6函數(shù)參數(shù)默認值14
2.1.7函數(shù)參數(shù)傳引用14
2.1.8函數(shù)重載15
2.1.9auto類型15
2.1.10基于范圍的for循環(huán)16
2.1.11動態(tài)內(nèi)存分配16
2.1.12統(tǒng)一的初始化方式18
2.1.13Lambda表達式18
2.1.14小節(jié)習題19
2.2面向?qū)ο蟪绦蛟O(shè)計19
2.2.1類和對象的概念19
2.2.2this指針21
2.2.3類的靜態(tài)成員21
2.2.4類成員的可訪問范圍22
2.2.5構(gòu)造函數(shù)24
2.2.6析構(gòu)函數(shù)25
2.2.7運算符的重載27
2.2.8函數(shù)對象28
2.2.9小節(jié)習題28
2.3模板與泛型程序設(shè)計29
2.3.1函數(shù)模板30
2.3.2類模板32
2.3.3標準模板庫35
2.3.4小節(jié)習題42
第3章線性表44
3.1順序表44
3.1.1順序表的概念和操作44
3.1.2C++中的順序表46
3.2鏈表47
3.2.1單鏈表47
3.2.2循環(huán)單鏈表51
3.2.3雙鏈表51
3.2.4靜態(tài)鏈表55
3.2.5C++中的鏈表56
3.3順序表和鏈表的選擇56
小結(jié)57
習題57
第4章枚舉與二分法59
4.1枚舉59
4.1.1案例: 八皇后問題(P0070)59
4.1.2案例: 奧數(shù)問題(P0100)60
4.1.3案例: 特殊密碼鎖(P0090)62
4.2二分法64
4.2.1案例: 網(wǎng)線主管(P0120)65
★4.2.2案例: 好斗的牛(P0130)66
小結(jié)68
習題68
第5章遞歸和分治70
5.1用遞歸進行枚舉71
5.1.1案例: N皇后問題(P0230)71
5.1.2案例: 奧數(shù)問題(P0100)的遞歸解法73
5.1.3案例: 全排列(P0240)74
5.2解決用遞歸形式定義的問題76
5.2.1案例: 波蘭表達式(P0250)76
★5.2.2案例: 分形盒(P0255)78
5.3用遞歸進行問題分解79
5.3.1案例: 上臺階(P0260)79
5.3.2案例: 算24(P0270)81
5.3.3案例: 放蘋果(P0280)82
5.3.4案例: 7的倍數(shù)取法有多少種(P0290)83
5.4分治84
★5.4.1案例: 求排列的逆序數(shù)(P0300)84
5.4.2案例: 漢諾塔問題(P0310)86
5.4.3案例: 快速冪87
小結(jié)88
習題88
第6章棧和隊列90
6.1棧90
6.1.1棧的概念和C++中的棧90
6.1.2案例: 括號配對(P0410)90
6.1.3案例: 后序表達式求值(P0420)92
★6.1.4案例: 中序表達式轉(zhuǎn)后序表達式(P0430)93
★6.1.5案例: 四則運算表達式求值(P0440)96
6.1.6案例: 合法出棧序列(P0450)98
★★6.2棧和遞歸的關(guān)系99
6.3隊列102
6.3.1基本實現(xiàn)102
6.3.2循環(huán)隊列103
6.3.3C++中的隊列105
★★6.3.4案例: 滑動窗口(P0460)106
★6.3.5案例: 用兩個棧模擬一個隊列109
6.4用鏈表實現(xiàn)棧和隊列109
小結(jié)110
習題110
第7章二叉樹113
7.1二叉樹的概念113
7.2二叉樹的性質(zhì)115
7.3二叉樹的表示117
7.3.1用類表示二叉樹117
7.3.2完全二叉樹的表示117
7.4二叉樹的遍歷118
7.4.1二叉樹的前序、后序、中序和按層次遍歷118
7.4.2案例: 根據(jù)二叉樹前中序序列建樹(P0570)121
★7.4.3案例: 求二叉樹的寬度(P0630)123
★★★7.4.4案例: 根據(jù)后序表達式建立表達式樹(P0580)124
★★7.4.5案例: 文本縮進二叉樹(P0560)126
★7.4.6非遞歸方式遍歷二叉樹127
★★7.5線索二叉樹129
7.6堆132
7.6.1堆的概念132
7.6.2堆的操作133
7.6.3建堆135
7.6.4堆的實現(xiàn)和優(yōu)先隊列135
7.7哈夫曼樹138
7.7.1哈夫曼樹的概念和構(gòu)造138
7.7.2案例: 柵欄修補(P0590)139
7.7.3哈夫曼編碼140
小結(jié)143
習題143
第8章樹、森林和并查集146
8.1樹的概念146
8.2樹的實現(xiàn)147
8.2.1直觀表示法147
8.2.2案例: 括號嵌套樹(P0740)148
8.2.3兒子兄弟表示法149
8.2.4案例: 樹轉(zhuǎn)兒子兄弟樹(P0750)150
8.2.5父結(jié)點表示法152
8.3森林152
8.4并查集153
8.4.1并查集的概念和用途153
8.4.2案例: The Suspects疑似病人(P0760)155
小結(jié)157
習題157
第9章字符串159
9.1字符串的編碼159
9.2字符串的實現(xiàn)160
9.3字符串的匹配算法161
9.3.1匹配算法161
★★9.3.2KMP字符串匹配算法162
小結(jié)166
習題166
第10章動態(tài)規(guī)劃168
10.1什么是動態(tài)規(guī)劃168
10.2動態(tài)規(guī)劃解題的一般思路172
10.3案例: 簡單背包問題(P0880)174
★★10.4案例: 不太簡單的出棧序列統(tǒng)計(P0890)176
★10.5案例: 最長上升子序列(P0900)177
★★10.6案例: 最長公共子序列(P0910)179
小結(jié)181
習題181
第11章圖的遍歷和搜索183
11.1圖的定義和術(shù)語183
11.2圖的表示185
11.2.1鄰接矩陣185
11.2.2鄰接表186
11.2.3鄰接表和鄰接矩陣的對比187
11.3圖的遍歷187
11.3.1深度優(yōu)先遍歷187
11.3.2案例: 深度優(yōu)先遍歷一個無向圖(P1020)189
11.3.3案例: 城堡的房間(P1030)192
11.3.4案例: 判斷無向圖是否連通及是否有回路(P1040)194
11.3.5廣度優(yōu)先遍歷196
11.4圖的搜索198
11.4.1概述198
11.4.2深度優(yōu)先搜索200
11.4.3案例: 走迷宮之一(P1050)204
11.4.4案例: 走迷宮之二(P1060)205
11.4.5案例: 走迷宮之三(P1070)205
11.4.6廣度優(yōu)先搜索206
11.4.7案例: 抓住那頭牛(P1080)207
11.4.8案例: “走迷宮之三”的廣搜解法(P1070)209
★★11.4.9案例: 拯救行動(P1100)210
11.5深搜和廣搜的選擇213
小結(jié)213
習題214
第12章圖論基礎(chǔ)應(yīng)用算法217
12.1最短路217
12.1.1單源最短路問題的Dijkstra算法217
12.1.2案例: 簡單的糖果分配(P1220)220
★12.1.3求每對頂點之間最短路的Floyd算法223
★12.1.4案例: 奶牛比賽(P1230)224
12.2最小生成樹226
12.2.1概述226
12.2.2最小生成樹的性質(zhì)228
12.2.3Prim算法229
12.2.4Kruskal算法231
★12.2.5案例: 團結(jié)真的就是力量(P1235)232
★★12.2.6案例: 北極網(wǎng)絡(luò)(P1240)235
12.3拓撲排序237
12.3.1拓撲排序的定義和算法237
12.3.2案例: 火星人家族樹(P1250)238
★12.4關(guān)鍵路徑240
12.4.1關(guān)鍵路徑的定義和算法240
★★12.4.2案例: 火星大工程(P1260)242
小結(jié)245
習題245
第13章排序248
13.1插入排序249
13.1.1直接插入排序249
13.1.2折半插入排序251
13.1.3希爾排序252
13.2選擇排序253
13.2.1簡單選擇排序253
13.2.2堆排序254
13.3歸并排序256
13.4交換排序259
13.4.1冒泡排序260
13.4.2快速排序261
13.5分配排序264
13.5.1桶排序264
13.5.2計數(shù)排序266
13.5.3基數(shù)排序267
★13.6外排序269
13.6.1置換選擇排序270
13.6.2多路歸并和敗者樹274
小結(jié)278
習題279
第14章查找281
14.1線性表查找281
14.1.1順序查找281
14.1.2二分查找282
14.1.3分塊查找285
14.2樹表查找286
14.2.1二叉查找樹286
★14.2.2平衡二叉樹(AVL樹)294
★14.2.3紅黑樹302
★14.2.4外存查找: B樹和B+樹308
14.2.5C++中的二叉查找樹317
14.3散列表321
14.3.1散列函數(shù)設(shè)計322
14.3.2散列表的插入和沖突消解324
14.3.3散列表的刪除和查找327
14.3.4散列表的效率分析328
14.3.5C++中的散列表329
小結(jié)329
習題331
第15章貪心算法335
15.1案例: 圣誕老人的禮物(P1370)335
15.2案例: 電影節(jié)(P1380)336
小結(jié)338
習題338
第16章數(shù)組和矩陣340
16.1數(shù)組340
16.2特殊矩陣的壓縮存儲342
小結(jié)344
習題344
附錄北京大學在線程序評測平臺OpenJudge使用說明346
參考文獻347