産品特色
編輯推薦
數據結構毫無疑問是計算機科學既經典又核心的課程之一,不管是從事計算機軟件還是硬件的開發工作,如果沒有係統地學習過數據結構或者沒有專心自學過,很容易被人打上“非專業”的標簽。對於任何在信息技術行業工作的專業人員或者想進入此行業的人來說,什麼時候開始學數據結構都不會晚,更不會過時。
從“數據結構”的名字看,它不僅僅隻是講授數據的結構以及在計算機內如何存儲和組織數據的方式,這些隻是它的錶麵現象。數據結構背後真正蘊含的是與之息息相關的算法,精心選擇的數據結構配閤恰如其分的算法就意味著數據或者信息在計算機內被高效率的存儲和高效率的處理。算法其實就是數據結構的靈魂,它既神秘又神奇“好玩”,當然對初學者也比較難,算法可以說是“聰明人在計算機上的遊戲”。
本書是一本綜閤而且全麵講述數據結構及其算法分析的教科書,為瞭便於高校的教學或者讀者自學,作者在描述數據結構原理和算法時文字清晰且嚴謹,為每個算法及其數據結構提供瞭演算的詳細圖解。另外,為瞭適閤教學中讓學生上機實踐或者自學者上機“操練”,本書為每個經典的算法都提供瞭C++語言編寫的完整範例程序實例(包含完整的源代碼),每個範例程序都不需要經過修改,直接通過編譯就可以運行,目的就是讓本書的學習者以這些範例程序作為參照迅速掌握數據結構和算法的要點。
全書的所有範例程序都可以在標準的C++語言編程環境中編譯通過並順利運行,我們在改編本書的過程中選用瞭免費的DevC++5.11集成開發環境,對原書的所有範例程序進行編譯、修改、調試和測試,並確保它們都可以準確無誤地運行。附錄A包含瞭“C/C++編譯程序的介紹與安裝”,其中重點就介紹瞭DevC++。附錄B則包含瞭“C++程序設計語言簡介”。
內容簡介
本書主要講解如何將數據結構概念用C++程序語言進行實作。本書將復雜的理論結閤圖文並茂的解說方式,並搭配豐富的圖錶及範例介紹,將數據結構中重要的觀念及演算方法加以詮釋,集中學習焦點。
本書適閤數據結構的初學者使用,也可以作為計算機相關專業的教科書。
作者簡介
鬍昭民,現任榮欽科技股份有限公司董事長,美國Rochester Institute of Technology計算機科學研究所畢業,長期從事信息教育及計算機圖書寫作的工作,並監製過多套遊戲及教學軟件的研發。
目錄
第1章 數據結構導論 1
1.1 數據結構簡介 2
1.1.1 數據結構的應用 2
1.1.2 算法 4
1.1.3 算法的描述工具 5
1.2 認識程序設計 7
1.2.1 高級程序設計語言 7
1.2.2 程序設計要領 8
1.3 程序設計的風格 8
1.3.1 自頂嚮下與模塊化設計 8
1.3.2 可讀性設計 8
1.3.3 控製結構設計 9
1.3.4 麵嚮對象設計 10
1.4 麵嚮對象設計與C++ 12
1.4.1 C++的麵嚮對象功能 12
1.4.2 類的基本概念 13
1.4.3 訪問權限關鍵詞 14
1.4.4 繼承關係 15
1.4.5 多態 16
1.5 遞歸算法 17
1.5.1 遞歸的定義 17
1.5.2 斐波拉契數列 19
1.5.3 漢諾塔問題 20
1.6 程序效率的分析 25
1.6.1 Big-oh 27
1.6.2 Ω(omega) 28
1.6.3 θ(theta) 28
本章習題 29
第2章 綫性錶 33
2.1 綫性錶的定義 34
2.1.1 綫性錶的用途 34
2.2 數組 35
2.2.1 一維數組 35
2.2.2 二維數組 37
2.2.3 多維數組 41
2.2.4 結構數組 45
2.2.5 C++的字符串 48
2.2.6 字符串數組 50
2.2.7 String類 51
2.2.8 指針數組 52
2.3 矩陣 54
2.3.1 矩陣的運算 54
2.3.2 稀疏矩陣 57
2.3.3 上三角形矩陣 60
2.3.4 下三角形矩陣 62
2.3.5 帶狀矩陣 66
本章習題 66
第3章 鏈錶 70
3.1 動態分配內存 71
3.1.1 C++的動態分配變量 72
3.1.2 動態配置數組 73
3.2 單嚮鏈錶 74
3.2.1 單嚮鏈錶的創建與遍曆 74
3.2.2 單嚮鏈錶插入新節點 76
3.2.3 單嚮鏈錶刪除節點 78
3.2.4 單嚮鏈錶的反轉 80
3.3 環形鏈錶 82
3.3.1 環形鏈錶中插入新節點 83
3.3.2 環形鏈錶節點的刪除 84
3.3.3 環形鏈錶的連接功能 86
3.4 雙嚮鏈錶 87
3.4.1 雙嚮鏈錶的建立與遍曆 87
3.4.2 雙嚮鏈錶中加入新節點 88
3.4.3 雙嚮鏈錶節點的刪除 90
3.5 鏈錶相關應用簡介 91
3.5.1 多項式錶式法 92
3.5.2 稀疏矩陣錶示法 95
本章習題 97
第4章 堆棧與隊列 103
4.1 堆棧簡介 104
4.1.1 堆棧的基本操作 105
4.1.2 用數組實現堆棧 105
4.1.3 用鏈錶實現堆棧 107
4.1.4 堆棧類樣闆的實現 108
4.1.5 老鼠走迷宮 109
4.1.6 八皇後問題 112
4.2 算術錶達式的錶示法 114
4.2.1 中序轉為前序與後序 115
4.2.2 前序與後序轉為中序 120
4.2.3 中序錶示法求值 122
4.2.4 前序法的求值運算 124
4.2.5 後序法的求值運算 125
4.3 隊列 125
4.3.1 隊列的基本操作 126
4.3.2 用數組實現隊列 126
4.4 隊列的相關應用 129
4.4.1 環形隊列 129
4.4.2 雙嚮隊列 133
4.4.3 優先隊列 134
本章習題 135
第5章 樹狀結構 147
5.1 樹的基本概念 148
5.1.1 專有名詞介紹 149
5.2 二叉樹 150
5.2.1 二叉樹的特性 150
5.2.2 特殊二叉樹簡介 152
5.3 二叉樹的存儲方式 153
5.3.1 一維數組錶示法 153
5.3.2 鏈錶錶示法 155
5.4 二叉樹的遍曆 156
5.4.1 中序遍曆 157
5.4.2 後序遍曆 158
5.4.3 前序遍曆 158
5.4.4 二叉樹節點的插入與刪除 160
5.4.5 二叉運算樹 165
5.5 綫索二叉樹 167
5.5.1 二叉樹轉為綫索二叉樹 167
5.6 樹的二叉樹錶示法 171
5.6.1 樹轉化為二叉樹 171
5.6.2 二叉樹轉換成樹 173
5.6.3 森林化為二叉樹 174
5.6.4 二叉樹轉換成森林 175
5.6.5 樹與森林的遍曆 176
5.6.6 確定唯一二叉樹 180
5.7 優化二叉查找樹 182
5.7.1 擴充二叉樹 182
5.7.2 霍夫曼樹 184
5.8 平衡樹 185
5.8.1 平衡樹的定義 185
5.9 高級樹狀結構的研究 187
5.9.1 決策樹 187
5.9.2 B樹 189
5.9.3 二叉空間分割樹 190
5.9.4 四叉樹與八叉樹 191
本章習題 192
第6章 圖形結構 202
6.1 圖形簡介 203
6.1.1 圖的定義 204
6.1.2 無嚮圖 204
6.1.3 有嚮圖 206
6.2 圖的數據錶示法 207
6.2.1 鄰接矩陣法 207
6.2.2 鄰接錶法 210
6.2.3 鄰接復閤鏈錶法 212
6.2.4 索引錶格法 214
6.3 圖的遍曆 217
6.3.1 深度優先遍曆法 217
6.3.2 廣度優先遍曆法 219
6.4 生成樹 221
6.4.1 DFS生成樹和BFS生成樹 222
6.4.2 最小生成樹 223
6.4.3 Kruskal算法 224
6.4.4 Prim算法 227
6.5 圖的最短路徑 228
6.5.1 單點對全部頂點 229
6.5.2 兩兩頂點間的最短路徑 232
6.6 AOV網絡與拓樸排序 235
6.6.1 拓樸排列簡介 236
6.7 AOE網絡 237
6.7.1 關鍵路徑 238
本章習題 239
第7章 排序 248
7.1 排序簡介 249
7.1.1 排序的分類 250
7.2 內部排序法 251
7.2.1 冒泡排序法 251
7.2.2 選擇排序法 254
7.2.3 插入排序法 256
7.2.4 希爾排序法 258
7.2.5 閤並排序法 260
7.2.6 快速排序法 260
7.2.7 堆積排序法 263
7.2.8 基數排序法 269
7.3 外部排序法 272
7.3.1 直接閤並排序法 272
7.3.2 k路閤並法 275
7.3.3 多相閤並法 276
本章習題 276
第8章 查找 286
8.1 常見的查找方法 287
8.1.1 順序查找法 287
8.1.2 二分查找法 288
8.1.3 插值查找法 290
8.1.4 斐波那契查找法 292
8.2 哈希查找法 295
8.2.1 哈希法簡介 296
8.3 常見的哈希函數 297
8.3.1 除留餘數法 297
8.3.2 平方取中法 297
8.3.3 摺疊法 298
8.3.4 數字分析法 299
8.4 碰撞與溢齣問題的處理 300
8.4.1 綫性探測法 300
8.4.2 平方探測 301
8.4.3 再哈希 301
8.4.4 鏈錶 301
本章習題 303
附錄A C/C++編譯程序的介紹與安裝 309
A.1 C/C++編譯程序簡介 310
A.2 Dev C++的安裝與介紹 313
附錄B C++程序設計語言簡介 319
B.1 C++語言的基本概念 320
B.2 C++語言的運算符與錶達式 323
B.3 C++語言的流程控製 327
B.4 C++語言的高級語法 332
B.5 C++語言與麵嚮對象概念 341
附錄C 數據結構專有名詞索引 349
精彩書摘
第7章 排序
隨著信息科技的逐漸普及與全球國際化的影響,企業所擁有的數據量成倍數的增長。無論是龐大的商業應用軟件,還是小至個人的文字處理軟件,每項工作的核心都與數據庫有著莫大的關係,而數據庫中最常見且重要的功能就是排序與查找,如圖7.1所示。
圖7.1 現在每項工作的核心都與數據庫關係密切
“排序”(sorting)是指將一組數據,按特定規則調換位置,使數據具有某種順序關係(遞增或遞減)。例如數據庫內可針對某一字段進行排序,而此字段稱為“鍵(key)”,字段裏麵的值我們稱之為“鍵值(key value)”。
7.1 排序簡介
在排序的過程中,數據的移動方式可分為“直接移動”和“邏輯移動”兩種。“直接移動”是直接交換存儲數據的位置,而“邏輯移動”並不會移動數據存儲的位置,僅改變指嚮這些數據的輔助指針的值。如圖7.2和圖7.3所示。
圖7.2 直接移動排序
圖7.3 邏輯移動排序
兩者間的優劣在於直接移動會浪費許多時間進行數據的移動,而邏輯移動隻要改變輔助指針指嚮的位置就能輕易達到排序的目的。例如在數據庫中,可在報錶中可顯示多項記錄,也可以針對這些字段的特性來分組並進行排序與匯總,這就是屬於邏輯移動,而不是去實際移動改變數據在數據文件中的位置,如圖7.4所示。
圖7.4 數據庫使用的是邏輯移動排序
7.1.1 排序的分類
排序通常按照數據量的多寡和所使用的內存可分為“內部排序”(internal sort)和“外部排序”(external sort),數據量小則可以全部加載到內存(如RAM)來進行的排序就稱為內部排序,大部分排序屬於此類。數據量大無法全部一次性加載到內存,必須藉助磁帶、磁盤等輔助存儲器進行排序則稱為外部排序。
以上隻是粗略的區分,其實隨著數據結構科學的進步,陸續提齣瞭如冒泡排序法、選擇排序法、插入排序法、閤並排序法、快速排序法、堆積排序法、希爾排序法、基數排序法、直接閤並排序法等等,各有其特色與應用場閤。
就排序法的選擇來說,當數據量相當大時,排序算法所花費的時間就顯得相當重要;一個排序法是否為一種有效率(efficiency)的排序法,取決於其時間復雜度,而時間復雜度的決定因素則是排序過程中數據的交換次數及其比較次數的多少。
排序前:21 34 45 56 77 81
排序後:81 77 56 45 34 21
【這種排序的時間復雜度就是最壞情況】
時間復雜度可分為最好情況(best case)、最壞情況(worst case)及平均情況(average case)。最好情況就是數據已完成排序,例如原本數據已經完成升序瞭,如果再進行一次升序所使用的時間復雜度就是最好情況。最壞情況是指每一個鍵值均須重新排列,簡單的例子就如原本為升序現在要重新排序成為降序,就是最壞情況。而空間復雜度就是指算法在執行過程所需占用的額外內存空間,排序法所使用到的額外空間越少,它的空間復雜度就越佳,例如冒泡法在排序過程中僅會用到一個額外的空間,在所有的排序算法中,這樣的空間復雜度就算是最好的。
7.2 內部排序法
在正式討論排序法之前,還要來討論排序的穩定度,因為並非所有排序法都是穩定排序法。所謂穩定的排序是指數據在經過排序後,兩個相同鍵值的記錄仍然保持原來的順序,如下例中30左的原始位置在30右的左邊(所謂30左和30右是指相同鍵值一個在左而一個在右),穩定的排序(Stable Sort)後30左仍應在30右的左邊,不穩定排序則有可能30左會跑到30右的右邊去:
原始數據順序: 30左 10 65 30右 21
穩定的排序: 10 21 30左 30右 65
不穩定的排序: 10 21 30右 30左 65
事實上,每一種排序方法都有其適用的情況與數據種類。建議大傢要充分瞭解排序算法的過程及其所花費的時間與空間復雜度。
7.2.1 冒泡排序法
冒泡排序法又稱為交換排序法,是從觀察水中氣泡變化構思而成,原理是從第一個元素開始,比較相鄰元素的大小,若大小順序有誤,則對調後再進行下一個元素的比較,就仿佛氣泡逐漸從水底逐漸冒升到水麵上一樣。如此掃描過一次之後就可確保最後一個元素是位於正確的順序。接著再逐步進行第二次掃描,直到完成所有元素的排序關係為止。
以下使用55、23、87、62、16數列的演示排序過程,這樣大傢可以清楚地知道冒泡排序法的具體流程。圖7.5為原始順序,圖7.6到7.9為排序的具體過程。
從小到大排序:
圖7.5 排序前的原始位置
圖7.6 冒泡排序的第一次掃描
第一次掃描會先拿第一個元素55和第二個元素23進行比較,如果第二個元素小於第一個元素,則進行互換。接著拿55和87進行比較,就這樣一直比較並互換,到第4次比較完後即可確定最大值在數組的最後麵。
圖7.7 冒泡排序的第二次掃描
第二次掃描也是從頭比較,但因為最後一個元素在第一次掃描就已確定是數組中的最大值,故隻需比較3次即可把剩餘數組元素的最大值排到剩餘數組的最後麵。
第三次掃描完,完成3個值的排序,如圖7.8所示。
圖7.8 冒泡排序的第三次掃描
第四次掃描完,即可完成所有排序,如圖7.9所示。
圖7.9 冒泡排序的第四次掃描
由此可知5個元素的冒泡排序法必須執行5-1次掃描,第一次掃描需比較5-1次,共比較4+3+2+1=10次
7.2.1
數列(43, 35, 12, 9, 3, 99) 用冒泡排序法(Bubble Sort)進行從小到大排序,在執行時前3次(Swap,互換)的結果各是什麼?
第一次互換的結果為(35, 43, 12, 9, 3, 99)
第二次互換的結果為(35, 12, 43, 9, 3, 99)
第三次交換的結果為(35, 12, 9, 43, 3, 99)
冒泡排序法的C++算法:
for (int i=5;i>0;i--)// 掃描次數
{
for (int j=0;j
{
if (data[j]>data[j+1])// 比較相鄰兩數,如第一個數較大則互換
{
int tmp;
tmp=data[j];
data[j]=data[j+1];
data[j+1]=tmp;
}
}
cout<<"第 "<<6-i<<" 次排序後的結果是:"; //把各次掃描後的結果打印齣來
for (int j=0;j<6;j++)
cout<
cout<
}
從以上算法可知,n個元素的冒泡排序法必須執行n-1次掃描,最壞情況和平均情況均需比較:(n-1) + (n-2) + (n-3) +…+ 3 + 2 + 1 = 次,時間復雜度為O(n2),最好情況隻需完成一次掃描,發現沒有進行互換的操作則錶示已經排序完成,所以隻做瞭n-1次比較,時間復雜度為O(n)。此排序法適用於數據量小或有部分數據已經過排序,而且過程中為相鄰兩者相互比較和對調,並不會更改其原本排列的順序,所以是穩定排序法。
7.2.2
請設計一個C++程序,並使用冒泡排序法來將以下的數列排序:6、5、9、7、2、8。
請參考程序CH07_01.cpp,本範例程序的運行結果如圖7.10所示。
圖7.10 使用冒泡排序的範例程序的運行結果
7.2.3
從上麵的程序可以看齣冒泡排序法有個缺點,就是不管數據是否已排序完成都固定會執行n(n-1)/2次。請設計一個C++程序,讓我們可以通過在程序中加入一個判斷語句來判斷何時可以提前結束程序,既可得到正確的排序結果,又提高瞭程序執行的效率。
請參考程序CH07_02.cpp,本範例程序的運行結果如圖7.11所示。
圖7.11 改進後的冒泡排序範例程序的運行結果
7.2.2 選擇排序法
圖解數據結構:使用C++ 下載 mobi epub pdf txt 電子書