因本人最近在惡補數據結構,學識經驗有限,如有不正之處望讀者指正,不勝感激;也望藉此平臺留下學習筆記以溫故而知新。這一篇博客主要是最近剛開始接觸大話數據結構一書,寫的通俗易懂,很多圖表幫忙理解,所以講隨手筆記分享至此,希望對您有所幫助。
數據結構緒論
數據結構的定義:
邏輯結構:集合、線性結構、樹形結構、圖形結構
物理結構:順序、鏈接
算法緒論
分析算法運行時間時,要把基本操作的數量與輸入規模關聯起來,即將基本操作的數量表示成輸入規模的函數
大O階算法時間複雜度:
1、用常熟1取代時間中的所有加法常熟
2、在修改後的運行次數函數中,只保留最高階項
3、如果最高階項存在且不是1,去除與這個項相乘的常數
順序結構和分支結構:O(1)
算法時間複雜度:
常數階、線性階、對數階、平方階
常用時間複雜度所耗費的時間從小到大依次是:
線性表(鏈表)
線性表
插入算法:
刪除算法:
線性表順序存儲結構的優缺點:
頭指針和頭結點的異同
單鏈表數據的讀取
單鏈表插入結點數據的思路
單鏈表刪除結點的思路代碼
單鏈表整表創建的算法思路:
單鏈表整表創建的代碼:
單鏈表整表刪除的算法思路
單鏈表整表刪除的算法代碼
單鏈表結構和順序存儲結構對比
其他鏈表結構1:靜態鏈表(用數組描述的鏈表)
靜態鏈表的插入:
1、將所有未被使用過的以及已經被刪除的分量用遊標連成一個鏈表
並將第一個結點作爲待插入新結點
2、在第i個元素之前插入數據
靜態表的刪除
1、釋放結點函數
2、刪除列表中結點數據
靜態鏈表特點
其他鏈表結構2:循環鏈表
其他鏈表結構3:雙向鏈表
雙向鏈表的插入
順序:先搞定s的前驅和後繼,在搞定後結點的前驅,最後搞定前結點的後繼
雙向鏈表的刪除
線性表總結
棧與隊列
棧:本質是線性表
棧頂:允許插入和刪除數據的一端
特點:後進先出(LIFO結構:Last In First Out)
棧的順序結構定義:
進棧:
出棧:
兩棧共享空間
插入元素的代碼
出棧:
棧的鏈式存儲結構(鏈棧)
進棧
出棧
棧有一個很重要的應用:在程序設計語言中實現了遞歸。
棧的應用:用於四則運算(採用後綴表達式,從左到右遍歷表達式的每個數字和符號,
遇到是數字就進棧,遇到是符號就將棧頂兩個數字出棧,進行運算,運算結果進棧)
隊列(先進先出FIFO,First In First Out)
本質:只允許一端進行插入操作(隊尾),另一端進行刪除的線性表(對頭)
隊列順序存儲
循環隊列
計算隊列長度公式:
循環隊列滿的條件是
循環隊列入隊代碼
循環隊列出隊代碼
隊列的鏈式存儲(只能尾進頭出的單鏈表)
鏈隊列入隊操作:
鏈隊列出隊操作
串
串的順序存儲
串的鏈式存儲
實現Index操作代碼:
KMP模式匹配算法原理
首先定義模式匹配字符串各位位置的變化爲一個數組,其函數定義如下
一個例子:
計算當前要匹配的串的數組
使用KMP實現Index操作
樹
樹相關結點定義:度
結點的層次:
數據結構對比
樹的存儲結構:雙親表示法、孩子表示法、孩子兄弟法
雙親表示法:data是數據域,parent是指針域
根據結點找雙親結點的時間複雜度爲o(1)
孩子表示法
方案一:統一度
方案二:每個結點指針域的個數等於該結點的度
方案一增加了空指針的浪費,方案二在運算時帶來時間上的損耗
是以改進得到如下孩子表示法
孩子兄弟表示法(把一顆複雜的樹變成了一顆二叉樹)
二叉樹
對於只有兩種結果的情形,都適合用樹狀結構來建模
滿二叉樹
完全二叉樹(如果編號爲i的結點與同樣深度的滿二叉樹中編號爲i的結點在
二叉樹中位置完全相同)
二叉樹性質:
1、在二叉樹的第i層上至多有2i-1個結點
2、深度爲k的二叉樹至多有2k-1個結點
3、對任何一顆二叉樹,如果其終端結點數爲n0,
度爲2的結點數爲n2,則滿足:n0=n2+1
4、具有n個結點的完全二叉樹的深度爲[log2(n)] + 1
其中[x]表示不大於x的最大整數
5、一顆有n個結點的完全二叉樹(深度爲[log2(n)] + 1)的結點按層編號,對任
一結點i有:
1 如果i=1,則結點是二叉樹的根;如果i>1,則其雙親是結點[i/2]
2 如果2i>n,則結點無左孩子,否則其左孩子是結點2i
3 如果2i+1>n,則結點i無有孩子,否則其右孩子是結點2i+1。
二叉樹的順序存儲結構(一般只用於完全二叉樹)
一顆完全二叉樹圖示
其順序存儲
二叉鏈表
結點結構圖
遍歷二叉樹
前序遍歷:ABDGHCEIF
中序遍歷:GDHBAEICF
後序遍歷:GHDBIEFCA
層序遍歷:ABCDEFGHI
二叉樹的前序遍歷算法:
二叉樹的中序遍歷算法
二叉樹的後序遍歷算法
注意:
已知前序遍歷和中序遍歷,可以唯一確定一顆二叉樹
已知後序遍歷和中序遍歷,可以唯一確定一顆二叉樹
但是:已知前序和後序,不能確定唯一一顆二叉樹
線索二叉樹
將一顆二叉樹進行中序遍歷後,將所有空指針改爲指向前驅和後繼結點的示例,
空心箭頭實線爲前驅,虛線黑箭頭爲後繼
即使改寫成這樣的雙向鏈表後,依然存在問題,如何區分某一結點的lchild是指向
左孩子還是指向前驅,rchild是指向右孩子還是指向後繼(增加0、1標識域)
其中,ltag爲0 指向結點的左孩子,爲1指向結點的前驅
rtag爲0 指向結點的右孩子,爲1指向結點的後繼
線索二叉樹的實現
中序遍歷線索化的遞歸函數代碼
二叉樹線索鏈表
二叉線索鏈表代碼(link=0, thread=1)
說明:如果在所用的二叉樹需要經常遍歷或者查找結點時需要某種遍歷序列中的前驅和
後繼,那麼採用線索二叉鏈表的存儲結構就是非常不錯的選擇
樹、森林與二叉樹的轉換
樹轉換爲二叉樹
示例:
森林轉換爲二叉樹
示例:
二叉樹轉換爲樹
1、加線。若某結點的左孩子結點存在,則將這個左孩子的右孩子結點,右孩子的右孩子
結點。右孩子的右孩子的右孩子的結點。。。,反正就是左孩子的n個右孩子結點都作爲
此結點的孩子。將該結點與這些右孩子結點用線連接起來
2、去線。刪除原二叉樹中所有結點與其右孩子結點的連線
3、層次調整。使之結構層次分明
示例:
二叉樹轉換爲森林
示例
說明:當以二叉鏈表作樹的存儲結構時,樹的先根遍歷和後根遍歷完全可以借用
二叉樹的前序遍歷和中序遍歷的算法來實現。
赫夫曼樹
構造一顆有n個葉子結點的二叉樹,每個葉子結點帶權w,每個葉子的路徑長度爲k,則
帶權路徑長度WPL最小的二叉樹稱作赫夫曼樹,也叫最優二叉樹
赫夫曼樹的構造:
具體過程:
結果如下:
赫夫曼編碼
設需要編碼的字符集已知,各個字符在電文中出現的次數獲頻率集合已知,
以字符集作爲葉子結點,以頻率作爲葉子結點的權重來構造一顆赫夫曼樹。
規定赫夫曼樹的左分支代表0,右分支代表1,則從根結點到葉子結點所經
過的路徑分支組成的0和1的序列便是該結點對應字符的編碼。
圖
圖的概念與定義
由頂點的有窮非空集合和頂點之間邊的集合組成,通常表示爲G(V,E),G表示一個圖,V是圖中頂點的集合,E是圖中邊的集合
無向圖的概念
在有向圖中,如果任意兩個頂點之間都存在方向互爲相反的兩條弧,則爲有向完全圖
假設有兩個圖,其中一個圖的所有頂點和邊都包含於另一個圖中,則稱這個圖爲子圖
特點:對於無向圖,邊數就是各頂點度數和的一半
對於有向圖,有向弧的條數等於各頂點的出度,也等於各頂點的入度
連通圖:
頂點間都是連通的就是連通圖,否則不是
連通分量:無向圖中的極大連通子圖
在有向圖中,對於每一對頂點,都存在路徑,則稱圖爲強連通圖
連通圖的生成樹:是一個極小的連通子圖,含有圖中全部頂點,但只有足以構成一棵樹的n-1條邊
圖的定義與術語總結
圖的存儲結構
圖的鄰接矩陣存儲方式是用兩個數組來表示圖,一個一維數組存儲圖中頂點信息,一個二維數組(稱爲鄰接矩陣)存儲圖中的邊或者弧的信息
通過這個矩陣,就有一下推斷
對於網而言,就是將0和1標識的有無改變成對應關係的權重值
圖的鄰接矩陣存儲結構的代碼實現
根據定義的結構,創建無向網圖
鄰接表
根據以上數據存儲結構,可以給出關於結點定義的代碼
基於結點定義的代碼,無向圖的鄰接表創建代碼如下
十字鏈表
有向圖的一種存儲方式
重新定義頂點表結點結構
重新定義邊表結構
鄰接多重表
對於無向圖的鄰接表
邊集數組
由兩個一維數組構成。一個是存儲頂點的信息,另一個是存儲邊的信息;這個邊數組每個數據元素由一條邊的起點下標、終點下標和權組成。
圖的遍歷
從圖中某一個頂點出發訪問其餘頂點,且使每一個頂點僅被訪問一次。
兩種常用方法:深度優先遍歷和廣度優先遍歷
深度優先遍歷(DFS):
從圖中某個頂點出發,訪問此頂點,然後從頂點未被訪問的鄰接點出發深度優先遍歷圖,直到圖中所有和頂點有路徑相通的頂點都被訪問到
使用鄰接矩陣的方式進行深度優先遞歸算法代碼
使用鄰接表的方式進行深度優先遞歸算法代碼
廣度優先遍歷(BFS):
逐漸擴大搜索範圍,類似於樹的層次遍歷
鄰接矩陣結構的廣度優先遍歷算法
說明:兩種遍歷算法在時間複雜度上一樣的,不同之處在於對頂點訪問的順序不同。深度優先更適合目標比較明確,以找到目標爲主要目的的情況;而廣度優先遍歷更適合在不斷擴大遍歷範圍時找到相對最優解的情況
最小生成樹
構造聯通網的最小代價生成樹
查找最小生成樹的算法有兩種:普里姆和克魯斯卡爾算法
普里姆算法:示例
說明:普里姆算法是以某頂點爲起點,逐步找各頂點上最小權值的邊來構建最小生成樹
克魯斯卡爾算法
首先使用邊集數組結構存儲數據
則得到如下數據表示:
克魯斯卡爾算法代碼
最短路徑
定義:
非網圖:兩頂點之間經過的邊數最少的路徑
網圖:兩頂點之間經過的邊上權值之和最少的路徑,並且路徑上的第一個頂點是源點,最後一個頂點是終點
迪傑斯特拉算法:按照路徑長度遞增的次序產生最短路徑的算法
具體代碼實現
說明:計算任一頂點到其餘所有頂點的最短路徑,其時間複雜度爲O(n3)
弗洛伊德算法
具體應用示例
因爲要求所有頂點到所有頂點的最短路徑,所以pathmatrix和shortpathtable都是二維數組
求最短路徑: