文章目錄
一、相關名詞解釋
1. 完全圖
- 無向圖中任意兩個頂點之間都存在邊,稱爲無向完全圖。 n個頂點,n(n-1)/2 條邊
- 有向圖中任意兩個頂點之間都存在相反的兩條弧,稱爲有向完全圖。 n個頂點, n(n-1)條邊
2. 連通圖/強連通圖
-
無向圖 中頂點v到頂點w有路徑存在,稱v和w連通。若任意兩個頂點都連通,
連通圖
若一個圖有n個頂點,並且邊數小於n-1,則此圖必是非連通圖
若一個圖有n個頂點,並且邊數大於n-1,則此圖必有迴路 -
有向圖 中頂點v到頂點w和頂點w到頂點v之間都有路徑,稱v和w 強連通 。若任意兩個頂點都連通,
強連通圖
3. 連通分量/極大連通子圖
- 無向圖中極大連通子圖稱爲連通分量;
- 有向圖中極大連通子圖稱爲強連通分量;
極小連通子圖指該連通子圖既保持圖的連通且包含的邊數最少;
4. 生成樹 (對於連通圖而言)
連通圖的生成樹是 包含全部頂點的一個極小連通子圖(即包含全部頂點且邊數最少)
若砍去生成樹的一條邊,則會變成非連通圖
若加上一條邊,則會形成一個迴路
5. 頂點的入度和出度
- 無向圖 的的全部頂點的度之和等於邊數的2倍
- 有向圖 的全部頂點的入度之和與出度之和相等,且與邊數相等
6. 簡單路徑
序列中的頂點和路徑不重複出現的路徑。
7. 迴路
路徑中第一個頂點和最後一個頂點相同的路徑
二、圖的存儲
鄰接矩陣法:(稠密圖)
圖的順序存儲結構
一維數組存儲頂點集,二維數組存儲邊集
無向圖的鄰接矩陣第i行(列)非零元素的個數表示該頂點的度
有向圖的鄰接矩陣第i行(列)非零元素的個數表示該頂點的出度(入度)
無向圖的鄰接矩陣是對稱的
鄰接表法:(稀疏圖)
圖的鏈式存儲結構
一個單鏈表表示該頂點的邊表;
各個單鏈表的頭指針和頂點採用順序存儲連接起來表示頂點表
鄰接表可以方便的找出一頂點的所有鄰邊,但確定兩結點之間是否有邊效率低下
在有向圖中,求一個給定結點的出度只需計算鄰接表中結點的個數,但求入度需要遍歷全部頂點的鄰接表
-
假設有n個頂點,e條邊的有向圖用鄰接表表示,則刪除與某個頂點v相關的所有邊的時間複雜度爲:
O(n+e)
首先刪除下標爲v的頂點表結點的單鏈表,邊數最多n-1,時間複雜度O(n);
再掃描所有邊表結點,刪除所有的頂點v的入邊,時間複雜度O(e);
十字鏈表
有向圖的另一種鏈式存儲結構。
鄰接多重表
無向圖的鏈式存儲結構。
三、圖的遍歷
廣度優先遍歷BFS(類似於層次遍歷)
基本思想 :利用 隊列
實現。
- 首先訪問起始頂點 V 並將其入隊
- V出隊,並遍歷V的所有鄰接點 w1,w2,….,wn並依次入隊
- w1出隊,並遍歷 w1 的全部鄰接點(不包括已經被訪問的點)
- w2出隊,並遍歷w2的全部鄰接點(不包括已經被訪問的點)
- … 以此類推
void BFS(Graph G, int v){
visit(v); //訪問初始結點
visited[v] = TRUE; //初始結點置已訪問標識
EnQueue(Q,v); //頂點v入隊
while(!isEmpty(Q)){
DeQueue(Q,v); //頂點v出隊
for(w = FirstNeighbor(G,v); w>=0; w = NextNeighbor(G,v,w)){ //循環遍歷v所有鄰接點
if(!visited[w]){
visit(w); //訪問頂點w
visited[w] = TRUE;
EnQueue(Q, w);
}
}
} //while
}
void BFSTraverse(Graph G){
for(i = 0; i<G.vexnum; i++)
visited[i] = FALSE;
InitQueue(Q); //初始化隊列
for(i = 0; i<G.vexnum;i++) //防止一次遍歷無法遍歷到全部結點(非連通圖)
if(!visited[i]) //若未被訪問
BFS(G,i);
}
深度優先遍歷DFS(類似於先序遍歷)
基本思想:利用 遞歸/棧
實現。當不能繼續向下訪問時,依次回退到最近的被訪問結點
- 首先訪問頂點V,並將其標記爲已訪問
- 然後訪問與頂點V的其中一個未被訪問的鄰接點W,並將其標記爲已訪問
- 再訪問W的其中一個未被訪問的鄰接點,並將其標記爲已訪問
- 依次類推… 當一個頂點所有的鄰接頂點都被訪問過時,則依次退回最近被訪問過的頂點
void DFS(Graph G, int v){
visit(v);
visited[v] = TRUE;
for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
if(!visited[v])
DFS(G,w); //遞歸
}
}
void DFSTraverse(Graph G, int v){
for(int i = 0 ; i<G.vexnum; i++)
visited[v] = FALSE;
for(int i = 0; i<G.vexnum; i++)
if(!visited[v])
DFS(G,i);
}
}
四、圖的應用
1. 最小生成樹
Prim算法
每次選取相對最小的邊並且互相連通。需保證無環
kruskal算法
每次選取最小的邊,無須保證此過程是否連通。需保證無環
2. 最短路徑
Dijkstra算法
該算法可以求得某一頂點到其餘各頂點的最短路徑。
算法思想:
- 設有兩個頂點集合 S 和 T,其中集合 S 中存放的是圖中已找到最短路徑的頂點,集合 T 中存放 的是圖中的剩餘頂點。
- 初始狀態時,集合 S 中只包含源點 V0,然後不斷從集合 T 中選取到頂點 V0 路徑最短的頂點 Vu 並加入集合 S 中,之後的路徑可通過該結點
- 集合 S 每加入一個新的頂點 Vu,都要修改 V0 到集合 T 中各個頂點的最短路徑的長度值。
- 不斷重 復這個過程,直至集合T中的頂點全部併入到 S 中爲止。
Floyd算法
每次都試圖在路徑上添加新的中間結點
3. 拓撲排序
什麼圖可以進行拓撲排序?
有向無環圖
基本思想 :每次去除一個入度爲0的結點和該與頂結點相連的邊
若圖中存在一條A——>B的路徑,則在拓撲排序中表示B事件在A事件的後面
4. 關鍵路徑
具有最大路徑長度的路徑稱爲關鍵路徑
只提高一條關鍵路徑上的關鍵活動速度並不能縮短整個工程的工期,只有加快所有關鍵路徑上的關鍵活動才能縮短工期
👉 👉 👉 個人博客 小牛肉的個人博客,歡迎來訪~👈 👈 👈