資料結構篇_知識點板塊_第六章圖
資料結構篇為本人考研時所寫筆記,包括知識點和程式設計思想兩大板塊,筆記內容依據王道資料結構考研書所寫,但比書本上知識更加生動形象,願本篇章能對您有所幫助
六、圖
(一)圖的基本概念
(二)圖的儲存
- 鄰接矩陣法(又稱陣列表示法):
① 用一個一維陣列儲存圖中頂點資訊,一個二維陣列儲存圖的邊資訊(不只是儲存了頂點的資訊)
② 對於帶權圖而言,若兩頂點之間不存在邊則用∞表示
③ 對於有向圖的第i行非零元素個數正好是頂點i的出度,列正好是入度
④ 稠密圖適合用該儲存結構
⑤ A^ n的元素A^ n[i][j]:即矩陣乘法,表示當路線長度為n時從i到j時只能找到A^n[i][j]條路徑
- 鄰接表法:
① 存在兩種結點:頂點表結點(表頭結點)和邊表結點(表結點),其中頂點表中包含頂點域(data)和邊表頭指標(firstarc),邊表(對有向圖稱為出邊表)包含鄰接點域(adjvex)和指向下一個鄰接邊的指標域
② 適合儲存稀疏圖
③ 計算有向圖的入度、度,找入邊不方便
④ 可採用逆鄰接表的儲存方式來加速求解給定頂點的入度
⑤ 表示法不唯一,各結點的連結次序是任意的
- 十字連結串列:
① 有向圖的鏈式儲存結構
② 一個十字連結串列表示確定一個圖
③ 頂點結點中包含data域(存放頂點相關的資料資訊),firstin域(指向以該頂點為弧頭的第一個弧結點),firstout域(指向以該頂點為弧尾的第一個弧結點,順著這個走可找到給定結點的出邊)
④ 弧結點中有5個域:尾域(tailvex)和頭域(headvex)分別指示弧尾和弧頭這兩個頂點在圖中的位置;鏈域hlink指向弧頭相同的下一條弧;鏈域t1ink指向弧尾相同的下一條弧;info域指向該弧的相關資訊。這樣,弧頭相同的弧就在同一個連結串列上,弧尾相同的弧也在同一個連結串列上
- 鄰接多重表:
① 無向圖的鏈式儲存結構
② 與十字連結串列類似,每條邊用一個結點表示,包含6個域:mark為標誌域(用以標記該條邊是否被搜尋過),ivex和jvex為該邊依附的兩個頂點一條依附於頂點jvex
在圖中的位置;ilink指向下一條依附於頂點ivex的邊:jlink 指向下的邊,info為指向和邊相關的各種資訊的指標域
③ 每個頂點也用一個頂點表示,包含兩個域:data域儲存該頂點的相關資訊,firstedge域指示第一條依附於該頂點的邊
④ 對無向圖而言,其鄰接多重表和鄰接表的差別僅在同一條邊在鄰接表中用兩個結點表示,而鄰接多重表中只有一個結點
鄰接矩陣 | 鄰接表 | 十字連結串列 | 鄰接多重表 | |
---|---|---|---|---|
空間複雜度 | O(|V|^2) | 無向圖O(|V|+2|E|)有向圖O(|V|+|E|) | O(|V|+|E|) | O(|V|+|E|) |
找相鄰邊 | 遍歷對應行或列時間複雜度為O(|V|) | 找有向圖的入邊必須遍歷整個鄰接表 | 很方便 | 很方便 |
操作 | ① 刪除邊很方便② 刪除頂點需要大量移動資料③ 求有向圖頂點的度、判斷圖中是否有邊較方便 | 無向圖中刪除邊或頂點都不方便 | 很方便 | 很方便 |
適用於 | 稠密圖 | 稀疏圖和其他 | 只能存有向圖 | 只能存無向圖 |
表示方式 | 唯一 | 不唯一 | 不唯一 | 不唯一 |
(三)圖的遍歷和圖的連通性
-
從圖中某一頂點出發訪遍圖中其餘頂點,且使每一個頂點僅被訪問一次,這一過程就叫做圖的遍歷
-
對鄰接表儲存的圖的深度遍歷稱DFS,對鄰接矩陣儲存的圖深度遍歷稱DFSM
對鄰接表儲存的圖的廣度遍歷稱BFS,對鄰接矩陣儲存的圖廣度遍歷稱BFSM
-
圖的遍歷演算法可用來判斷圖的連通性
-
圖的廣度優先生成樹的樹高比深度優先生成樹樹高小或相等
-
程式碼編寫注意:在BFSTraverse()或DFSTraverse()中添加了第二個for迴圈,再選取初始點,繼續進行遍歷,以防止次無法遍歷圖的所有頂點
-
對於無向圖,上述兩個函式呼叫BFS(G,i)或DFS (G,i)的次數等於該圖的連通分量數
對於有向圖,因為一個連通的有向圖分為強連通的和非強連通的,它的連通子圖也分為強連通分量和非強連通分 量,而非強連通分量一次呼叫 BFS(G,i)或DFS(G,i)無法訪問到該連通分量的所有頂點
(四)圖的應用
-
必須學會手工模擬給定圖的各個演算法的執行過程,此外還需掌握對給定模型建立相應的圖去解決問題的方法
-
最小生成樹或最小支撐樹(MST):
① 概念:對於一個帶權連通無向圖,所有生成樹的集合中權值之和最小的那棵生成樹
② 假設G={V,E}是連通圖,其最小生成樹T=(U,E_T)(E_T是最小生成樹中邊的集合)
③ 性質:
(1) 最小生成樹的樹形不唯一,當圖的各邊權值互不相等時,最小生成樹是唯一的
(2) 當G本身是一棵樹時,G的最小生成樹就是它本身
(3) 最小生成樹的邊權值之和是唯一的,而且是最小的
(4) 邊數=頂點數-1
- Dijkstra:
① Dijkstra提出的一種按路徑長度遞增序產生各頂點最短路徑的演算法。
② 按路徑長度遞增序產生各頂點最短路徑:按長度遞增的次序生成從源點s到其它頂點的最短路徑,則當前正在生成的最短路徑上除終點以外,其餘頂點的最短路徑均已生成(將源點的最短路徑看作是已生成的源點到其自身的長度為0的路徑)
③ 按照邊的權值由小到大的順序,考察G的邊集E中的各條邊。(加邊法)
- 有向無環圖(DAG圖)描述表示式:
① 描述含有公共子式的表示式的有效工具
② 與二叉樹表示的區別:可以有效實現對相同子式的共享(頂點中不可能出現重複的運算元),從而節省儲存空間
③ 有向無環圖描述表示式形態不唯一
④ 對於化簡題的解題方法
(1) 把各運算元不重複的排成一排
(2) 標出各個運算子的生效順序
(3) 按順序加入運算子,注意“分層”(若運算子A在運算子B的上一層說明A基於B/基於B這層其他運算子的計算結果而進行的下一步計算)
(4) 從底向上逐層檢查同層的運算子是否可以合體
- 拓撲排序
① AOV網(又稱頂點表示活動的網路):若用DAG圖表示一個工程,其頂點表示活動,用有向邊<V_i,V_j>表示活動V_i必須先於V_j進行
② 是一個有向無迴路的圖
③ 任何V_i不能以自己作為自己的前驅或後繼
④ 拓撲排序:由一個有向無環圖的頂點組成的序列,且滿足:
(1) 每個頂點出現且只出現一次
(2) 若頂點A在序列排在頂點B前,則在圖中不存在從頂點B到頂點A的路徑
⑤ 每個AOV網都有一個或多個拓撲排序
⑥ 若圖中無環,也可用深度優先遍歷進行拓撲排序,此時按DFS函式先後記錄的結點序列為逆向的拓撲有序序列
⑦ 寫拓撲排序的步驟(演算法思想,近期期末考了):
(1) 從AOV網中選擇一個沒有前驅的頂點並輸出(若選擇的是沒有後繼則是逆拓撲排序)
(2) 從網中刪除該頂點和所有以它為起點的有向邊
(3) 重複①②直到為空或不存在無前驅結點的頂點為止,後一種說明有向圖中必然存在環
⑧ 用鄰接表儲存時間複雜化度O(|V|+|E|)
用鄰接矩陣儲存時間複雜化度O(|V|^2)
⑨ 注意:
(1) 若各個頂點已經排在一個線性有序的序列中,每個頂點有唯一的前驅後繼關係,則拓撲排序的結果唯一
(2) 若鄰接矩陣是三角矩陣,則存在拓撲序列(不一定唯一),反之則不一定成立
(3)若兩個結點之間不是祖先或子孫關係,則它們在拓撲排序中的關係是任意的(前後關係任意),因此使用棧和佇列都可以,因為進棧或佇列的都是入度為0的結點,此時入度為0的所有結點是沒有關係的
(4) 若有向圖的拓撲排序唯一,則圖中每個頂點的入度和出度不一定最多為1
(5) 有向無環圖的拓撲排序序列唯一併不能唯一確定一個圖
(6) 有向圖為一個無環圖則一定存在拓撲序列
- 關鍵路徑:
① AOE網(又稱用邊表示活動的網路):在帶權有向圖中,以頂點表示事件,以有向邊表示活動,以邊上權值表示完成該活動的開銷
② 是帶權的有向無環圖
③ 開始頂點(源點):僅有的一個入度為0的頂點
結束頂點(匯點):僅有的一個出度為0的頂點
關鍵路徑長度:完成整個工程的最短時間,即關鍵路徑上各活動花費開銷總和
工程結束:所有路徑上的活動都已完成
④ 求解關鍵路徑步驟:
(1) 從源點出發,令ve(源點)=0,按拓撲有序求其餘頂點的最早發生時間ve()
(2) 從匯點出發,令vl(匯點)= ve(匯點),按逆拓撲有序求其餘頂點的最遲發生時間vl()
(3) 根據各頂點的ve()值求所有弧的最早開始時間e()
(4) 根據各頂點的vl(Q值求所有弧的最遲開始時間l()
(5) 求AOE網中所有活動的差額d(0, 找出所有d()= 0的活動構成關鍵路徑
⑤ 注意:
(1) 當縮短到一-定程度時, 關鍵活動可能會變成非關鍵活動
(2) 可能有多條關鍵路徑,只提高一條關鍵路徑上的關鍵活動速度並不能縮短整個工程的工期,只有加快那些包括在所有關鍵路徑上的關鍵活動才能達到縮短工期的目的。
(3) 關鍵活動一定位於關鍵路徑上
參量及計算 | ||
---|---|---|
參量 | 概念 | 計算方法 |
事件V_k的最早發生時間ve(k) | 從源點到該頂點的最長路徑長度決定了所有從此結點開始的活動能夠開工的最早時間 | 按從前往後的順序計算(選取最大的,因為一個結點開始執行要求前面的結點都已執行完,即拓撲排序的入度為0)(選最大的) |
事件V_k的最遲發生時間vl(k) | 在不推遲整個工程完成的前提下,該事件最遲必須發生的時間 | 按從後往前的順序計算(選最小的) |
活動a_i的最早開始時間e(i) | 活動弧的 起點表示的事件的最早發生時間 | e(i)=ve(k) |
活動a_i的最早開始時間l(i) | 活動弧的終點所表示的事件最遲發生時間與該活動所需時間之差 | 若<vk,vj>表示活動a_i,則有l(i)=vl(j)-Weight(vk,vj) |
活動a_i的時間餘量d(i) | d(i)=0的活動就是關鍵活動 | d(i)=l(i)-e(i) |