數據結構(C語言版) 第7章 圖
《數據結構(C語言版) 第7章 圖》由會員分享,可在線閱讀,更多相關《數據結構(C語言版) 第7章 圖(49頁珍藏版)》請在裝配圖網上搜索。
1、第7章 圖
1 邏輯結構
1.1 定義
G = (V, E) V是頂點集,E是頂點間二元關系的集合
內涵越小,外延越大
與樹的區(qū)別:
①樹有特殊的根結點;
②樹的結點和關系能分成互不相交的若干子集
圖的分類:
無向圖
有向圖
邊:二元關系是無序的。
弧:二元關系是有序的。
(vi,vj):vi,vj互為鄰接點
2、2)
V2={v1,v2,v3,v4}
E2={
3、、區(qū)域連通的規(guī)劃問題…… ④進度組織:工程進度管理…… 1.4 概念 思路:考慮圖的復雜應用,提供簡化問題的思路。 1.4.1 圖的分類 著眼點:存儲結構的選擇。 無向完全圖 邊數:n*(n-1)/2 有向完全圖 弧數:n*(n-1) 稀疏圖 邊數≈頂點數 稠密圖 邊數≈頂點數2 帶權圖 邊或頂點帶權值 著眼點:圖的分解。 子圖 V(B)∈V(A),E(B)∈E(A),稱圖B是圖A的子圖。 1.4.2 頂點的參數 度 無向圖中,依附于某頂點的邊數 入度 有向圖中,以某頂點為弧尾的弧數 出度 有向圖中,以某頂點為弧頭的弧數
4、 度的應用:以下哪個圖能夠一筆畫完成?為什么? 一筆畫問題的本質:圖結構中的邊遍歷問題。 應用領域:車間/廠房布置、行走路線的安排、交通設計… 1.4.3 有關路徑 著眼點:頂點間的聯系。 頂點間路徑 Vi,……,Vj 頂點間連通 若從Vi到Vj有路徑,稱Vi到Vj是連通的。 路徑長度 路徑上邊/弧的數目。 簡單路徑 路徑中所有頂點各不相同。 回路 路徑中,起點和終點是同一頂點。 簡單回路 除起點和終點外,其余頂點各不相同。 1.4.4 有關連通 著眼點:將不連通圖簡化為連通圖。 連通圖 無向圖中,任意二個頂點之間是連通的。
5、 無向圖的 連通分量 無向圖的極大連通子圖。 強連通圖 有向圖中,任意二個頂點之間存在來往路徑。 有向圖的 強連通分量 有向圖的極大強連通子圖。 1.4.5 生成樹 著眼點:將圖簡化為樹。 無向圖 生成樹 連通無向圖中,n個頂點和n-1條邊,構成的連通子圖。(原連通圖的極小連通子圖) 生成森林 不連通的無向圖中,各連通分量的生成樹的集合。 有向圖 生成樹 強連通有向圖中,n個頂點和n-1條弧,構成的單向連通子圖(vi、vj間存在一條路徑)。 一個頂點入度為0,其余頂點入度為1。 生成森林 不強連通的有向圖中,各有強連通分量的生成樹的集合。
6、 第7章 圖 2 圖的存儲結構 存儲結構應該包含: ①頂點的信息;②邊/弧的信息;③權的信息。 2.1 鄰接矩陣 2.1.1 結構圖 0, 1, 1, 0 1, 0, 0, 1 1, 0, 0, 1 0, 1, 1, 0 0, 4, 2, Inf 4, 0, Inf, 8 2, Inf, 0, 1 Inf, 8, 1, 0 0, 4, 2, Inf Inf, 0, Inf, 8 Inf, Inf, 0, Inf Inf, Inf, 1, 0 2.1.2 類的定義 cons
7、t double Inf=10000;
struct Edge
{ int v1,v2;
double weight;
};
class Mgraph // 簡化版,只存儲了邊/弧的信息。
{ int m_N;
vector
8、浪費多。
2.1.2 (無向圖的)類的實現
// 構造函數
MGraph::MGraph(int n)
{ m_N = n;
m_Es=new vector
9、 i 10、鄰接表
2.2.1 結構圖
圖的變化特征:頂點變化少,關系變化多。
頂點表: 順序結構。邊/弧表:動態(tài)鏈表。
帶權圖的鄰接表
2.2.2 類的定義
struct ArcNode // 邊、弧結構
{ int adjvex; // 鄰接點、弧頭的編號
double weight;
ArcNode *nextarc;
};
template 11、T>
class ALGraph
{ int m_N;
vector 12、= vs.size();
m_Data.resize(m_N);
for(int i=0; i 13、 ArcNode *p=new ArcNode;
p->adjvex=v2; p->weight=es[i].weight;
p->nextarc=m_Data[v1].firstarc;
m_Data[v1].firstarc = p;
}
}
// 計算有向圖中頂點i的出度
template 14、rn n;
}
// 計算有向圖中頂點i的入度
template 15、變化
原圖的結構
刪除頂點2之后的圖結構
2.3 逆鄰接表
2.3.1 結構圖
鄰接表(出邊表)
逆鄰接表(入邊表)
思考:根據鄰接表繪制逆鄰接表。
2.3.2 類的定義
同鄰接表類
2.4 十字鏈表
2.4.1 結構圖
將鄰接表、逆鄰接表合二為一。
主要用于表示有向圖。
和稀疏矩陣的十字鏈表結構相比:本質一樣。細節(jié)差別在于:行頭表和列頭表合并為了頂點表。
等價結構:
2.2.2 類的定義
struct ArcNode // 弧結構
{ int tailvex; // 弧尾的編號
int 16、headvex; // 弧頭的編號
double weight;
ArcNode *tlink; // 指向弧尾相同的弧結點
ArcNode *hlink; // 指向弧頭相同的弧結點
};
template 17、ata; // 頂點向量
………………
};
2.5 鄰接多重表
2.4.1 結構圖
無向圖的鄰接表有50%的冗余。精簡方法:每條邊對應一個邊結點。
主要用于表示無向圖。
鄰接多重表結構
2.4.2 類的定義
struct EdgeNode // 邊、弧結構
{ int ivex; // 第一鄰接點編號
int jvex; // 第二鄰接點編號
double weight;
ArcNode *ilink; // 指向第一鄰接點編號為i的邊結點
ArcNode *jlink; // 指向第二鄰接點編號為j的邊結 18、點
};
template 19、加以識別。
3.1 深度優(yōu)先搜索DFS(Depth First Search)
3.1.1 算法
①設置一個標記數組,設所有頂點都未曾被訪問;
②從起點v出發(fā),訪問此頂點,同時設置訪問標記;
③依次從v的未被訪問過的鄰接點出發(fā)進行DFS;
(效果:所有與v連通的頂點都被訪問過)
④若所有頂點都已訪問,則完成;否則,另擇起點v,轉至②。
圖的邏輯結構
圖的鄰接表存儲結構
以頂點0為起點的DFS:0,1,4,3,2
以頂點3為起點的DFS:3,1,4,2,0
3.1.2 算法實現(遞歸)
// 帽子函數
template 20、or 21、),vs1.end());
}
return vs;
}
template 22、ed[w]==false)
DoDFSTraverse(w,visited,vs);
}
}
思考1:與樹的遞歸遍歷算法的共性。
思考2:時間復雜度?
思考3:計算DFS生成樹的各邊。
思考4:若采用鄰接矩陣結構,程序如何調整?
3.1.3 調試示例
紅色邊:構成DFS生成森林,稱為樹邊。
結點中的左數字:開始訪問該結點的步驟;
結點中的右數字:完成訪問該結點的所有鄰接點的步驟;
3.1.4 調試中的深入思考
搜索過程中,邊的分類:
回邊:子孫結點指向祖先結點。
前向邊:祖先結點指向子孫結點。
交叉邊:子樹/樹之間 23、的邊。
應用:若在DFS過程中,沒有發(fā)現回邊,則該圖無環(huán)。
3.1.5 判斷無向圖中是否是連通,并計算連通分量的個數
int ALGraph 24、sited,vs1); n++;
vs.insert(vs.end(),vs1.begin(),vs1.end());
}
return n;
}
3.1.5 判斷無向圖中是否有回路
// 不適用于有向圖
template 25、rcle(v,visited)==true)
return true; // 存在環(huán)
return false; // 所有連通分量中,不存在環(huán)
}
template 26、 return true; // w已被訪問過,即發(fā)現環(huán)路
if(DoHasCircle(w,visited))
return true; // 在以w為起點的DFS中發(fā)現環(huán)路
}
return false; // 在以v為起點的DFS中,沒有發(fā)現環(huán)路
}
3.2 廣度優(yōu)先搜索BFS(breadth first search)
3.2.1 算法
①設所有頂點都未曾被訪問;
②將起點編號加入隊列,同時設置訪問標記;
③取隊首元素,設為v,訪問結點v;
④依次將v的各個未被訪問過的頂點加入隊列,同時設置訪問標記;
⑤若隊 27、列不空,則循環(huán)執(zhí)行③④,否則⑥;
⑥若所有頂點都已訪問,則完成;否則,另擇起點V,轉至②。
已知鄰接表,求遍歷序列。
以頂點0為起點的BFS:0,1,3,4,2
以頂點3為起點的BFS:3,1,0,4,2
3.2.2 算法實現
// 帽子函數
template 28、m_N; v++)
if(visited[v]==false)
{ vs1.clear();
DoBFSTraverse(v,visited,vs1);
vs.insert(vs.end(),vs1.begin(),vs1.end());
}
return vs;
}
template 29、> Q; ArcNode *p;
Q.push(v); visited[v]=true; // 步驟②
while(!Q.empty()) // 步驟⑤
{ v=Q.front(); Q.pop();
vs.push_back(m_Data[v].data); // 步驟③
// 步驟④
for(ArcNode *p=m_Data[v].firstarc; p; p=p->nextarc)
{ int w=p->adjvex;
if(visited[w]==false)
30、 { Q.push(w); visited[w]=true; }
}
}
}
思考1:與樹的層次遍歷算法的共性。
思考2:時間復雜度?
思考3:計算BFS生成樹的各邊。
思考4:計算起點到其余各頂點的最短路徑。
3.2.3 調試示例
紅色邊:構成BFS生成森林,稱為樹邊。
結點數字:距離起點的路徑長度
3.4 生成樹、生成森林的存儲結構(擴展思考)
在遍歷中,如何將生成樹、生成森林,以孩子兄弟法存儲起來?
圖的鄰接表結構
圖的生成森林的二叉鏈表結構
3.5 關節(jié)點、 31、重連通分量(擴展思考)
3.5.1 概念
關節(jié)點
若刪除某頂點及其關聯各邊,圖的一個連通分量將分割為多個連通分量,則該頂點是關節(jié)點。
重連通分量
沒有關節(jié)點的連通圖。
圖的連通度
若在連通圖上至少要刪除k個頂點才能破壞圖的連通性,則該圖的圖的連通度為k。
實際意義:連通度等價于系統(tǒng)的可靠度。
算法:在DFS生成樹,根結點至少有2個子結點,則為關節(jié)點。
第7章 圖
專題1 圖的非遞歸深度遍歷算法
1.1 狀態(tài)的定義
struct Status // 遍歷狀態(tài)類
{ int v; // 遍歷中的當前頂點編號
ArcNode *p; 32、// 當前頂點已經訪問的弧結點的指針
};
1.2 與遞歸函數完全相同的帽子函數
template 33、 vs.insert(vs.end(),vs1.begin(),vs1.end());
}
return vs;
}
1.3 借助狀態(tài)棧的回溯法
// 約定每個頂點被訪問之后,再進棧
與樹先根算法的區(qū)別:訪問標記的處理
template 34、atus s1={v,m_Data[v].firstarc}; S.push(s1);
while( !S.empty() )
{ Status &s=S.top(); // s是棧頂狀態(tài)的引用
// 尋找v的下一個未訪問過的鄰接點
for(; s.p; s.p=s.p->nextarc)
if(visited[s.p->adjvex]==false) break;
if(s.p)
{ int w=s.p->adjvex; // 頂點w未訪問過
vs.push_back(m_Data[w].data); v 35、isited[w]=true;
Status nexts;
nexts.v=w; nexts.p=m_Data[w].firstarc;
S.push(nexts);
}
else
S.pop(); // 以v為起點的搜索已經完畢
}
}
1.4 調試案例
訪問0
訪問1
訪問4
訪問3
訪問2
第7章 圖
專題2 地圖著色問題
2.1 地圖著色問題及其邏輯結構
設一張地圖有n個區(qū)域,用不多 36、于4種顏色對這些區(qū)域進行著色,相鄰區(qū)域應具有不同的顏色。
區(qū)域圖
邏輯結構圖
2.2 地圖著色判斷問題
試設計算法,以一種著色方案為輸入,算法對該著色方案進行考察,判別是否滿足著色要求。
// colors[0]...colors[m_N-1]存儲了所有區(qū)域的顏色值
template 37、 if(colors[p->adjvex]==colors[i]) return false;
return true;
}
// colors[0]...colors[n-1]存儲了部分區(qū)域的顏色值
template 38、->adjvex]==colors[i])
return false;
return true;
}
2.3 計算所有的地圖著色方案
template 39、
}
template 40、置為color顏色
if(Check(Colors,i+1)) // 剪枝法:檢查局部解的合理性
GetAllColors(i+1,Colors,allColors);
}
}
2.3 小結
本質上,窮舉所有的著色方案,是遍歷4叉樹所有葉子結點的過程。效率不高,但配合剪枝法的應用,能較好的改善算法性能。
作業(yè)與上機
1 圖的鄰接表類
建立鄰接表類,深度、廣度遍歷之,盡可能的豐富鄰接表類的成員函數;
方向1:計算生成樹/生成森林的弧向量,進而建立生成樹/生成森林的樹的存儲結構。
方向2:判別圖中是否存在回路;
方向3:計算頂點之間的 41、最短的路徑長度;
方向4:計算圖中的關節(jié)點,進而計算圖的連通度;
方向5:參照樹的非遞歸遍歷算法,實現圖的非遞歸深度遍歷算法。
方向6:計算地圖著色的一個/所有著色方案。
2 圖的應用
Prim算法、Kruskal算法
Dijkstra算法、Floyd算法。
拓撲排序算法、關鍵路徑算法。
第7章 圖
4 最小生成樹
4.1 概念
最小生成樹:各邊權值之和最小的生成樹。
原圖
生成樹一
生成樹二
生成樹三
4.2 Prim算法
4.2.1 算法思路
設圖G=(V,E),從起點v出發(fā),構造最小生成樹T=(VT,ET)。
42、①初始化VT={v},ET={};
②找權值最小的(Vp,Vq), Vp∈VT, Vq∈V-VT;
③將(Vp,Vq)并入ET,同時Vq并入VT;
④重復②③步驟n-1次。
4.2.2 數據結構
①圖的結構
因需要頻繁地讀取邊的權值,所以采用鄰接矩陣。
調試案例:以頂點4為起點,構造最小生成樹。
M_Data:
{{ 0, 2,Inf,Inf,Inf, 7, 3,Inf,Inf},
{ 2, 0, 4,Inf,Inf,Inf, 6,Inf,Inf},
{Inf, 4, 0, 2,Inf,Inf,Inf, 2,Inf},
{Inf,I 43、nf, 2, 0, 1,Inf,Inf, 8,Inf},
{Inf,Inf,Inf, 1, 0, 6,Inf,Inf, 2},
{ 7,Inf,Inf,Inf, 6, 0,Inf,Inf, 5},
{ 3, 6,Inf,Inf,Inf,Inf, 0, 3, 1},
{Inf,Inf, 2, 8,Inf,Inf, 3, 0, 4},
{Inf,Inf,Inf,Inf, 2, 5, 1, 4, 0}
};
②輔助結構
針對:找權值最小的(Vp,Vq), Vp∈VT, Vq∈V-VT;
設計結構:VT外每個頂點到V 44、T的最短距離。
struct ShortDist // 表示某頂點到VT的最短距離及對應頂點
{ float Distance; // VT外頂點到VT的最短距離
int VexInTree;// VT對應的頂點編號
};
vector 45、NF
INF
2
SDs[i].Distance=0的含義:頂點i已在生成樹中
4.2.3 算法及分析
① 初始化SDs;
② 在SDs中,找出Distance最小非0值的下標k;
③ (SDs[k].VexInTree,k)為生成樹的邊;
k是樹外某點,SDs[k].VexInTree是樹內某點;
④ SDs[k].Distance=0,即頂點k并入生成樹;
⑤ 若cost[k][i] 46、ee
4
4
4
4
4
4
4
4
4
Distance
M
M
M
1
0
6
M
M
2
第一次循環(huán)后
VexInTree
4
4
3
4
4
4
4
3
4
Distance
M
M
2
0
0
6
M
8
2
第二次循環(huán)后
VexInTree
4
2
3
4
4
4
4
2
4
Distance
M
4
0
0
0
6
M
2
2
設圖頂點數為n,時間復雜度是O(n2),空間復雜度是O(n)。
4.2.4 算法實現一:求MST的所有邊
vector 47、ge> MGraph::Prim1(int startv)
{ int n=m_Es->size();
vector 48、小非0值的下標k
if(SDs[j].Distance!=0 && SDs[j].Distance 49、tance)
{ SDs[j].Distance=(*m_Es)[k][j]; SDs[j].VexInTree=k; }
}
return tree;
}
4.2.5 算法實現二:求MST的樹結構
// 生成一棵雙親表示法的樹,存于tree中
vector 50、xInTree=startv;
SDs[i].Distance=(*m_Es)[startv][i];
}
for(i=0; i 51、 tree[i].weight=SDs[k].Distance;
SDs[k].Distance=0; // 將頂點k納入生成樹中
for(j=0; j 52、4
-1
8
8
2
4
結構解釋
4.3 Kruskal算法
4.3.1 算法思路
①盡可能選擇n-1條權值最小的邊;
②但不能構成回路。
4.3.2 算法步驟
①初始化VT=V,ET={},即n個頂點是n個連通分量;
②選擇權值最小的邊(Vp,Vq);
③若Vp、Vq不屬于同一連通分量,將(Vp,Vq)并入ET;否則,舍棄。
④重復②③,直至選取了n-1條邊。
4.3.3 連通分量表示與合并
連通分量:采用子集樹的存儲結構。
vector 53、并:子集樹的合并。
4.3.4 數據結構
struct Edge
{ int v1,v2;
double weight;
bool operator<(Edge &e)
{ return weight 54、d());
}
vector 55、ends)
{ parents[begins]=ends; // 合并子集樹
tree[k] =m_Es[i]; k++;
if(k==m_N)
return tree; // 找到了全部的樹邊
}
}
return tree;
}
// 計算頂點v所屬的連通分量的編號
int Graph::Find(vector 56、,8:1
4,8:2 0,1:2
2,7:2 2,3:2
0,6:3 6,7:3
1,2:4 7,8:4
5,8:5 4,5:6
1,6:6 0,5:7
3,7:8
三元組
begins
ends
0
1
2
3
4
5
6
7
8
初始化
-1
-1
-1
-1
-1
-1
-1
-1
-1
3,4:1
3
4
-1
-1
-1
4
-1
-1
-1
-1
-1
6,8:1
6
8
-1
-1
-1
4
-1
-1
8
-1
-1
4,8:2
4
8
-1
57、-1
-1
4
8
-1
8
-1
-1
0,1:2
0
1
1
-1
-1
4
8
-1
8
-1
-1
2,7:2
2
7
1
-1
7
4
8
-1
8
-1
-1
2,3:2
7
8
1
-1
7
4
8
-1
8
8
-1
0,6:3
1
8
1
8
7
4
8
-1
8
8
-1
6,7:3
8
8
1,2:4
8
8
7,8:4
8
8
5,8: 58、5
5
8
1
8
7
4
8
8
8
8
-1
4.3.7 性能分析
設圖的頂點個數為n,邊數為e。邊數組已經按權值有序。
空間復雜度: O(n)
“選邊”的時間復雜度: 最好O(n); 最差O(e)
“求子集”的時間復雜度:最好O(log2n);最差O(n)
4.4 暢想
Prim算法
適合稠密圖
Kruskal算法
適合稀疏圖
感受“貪心法”:用局部最優(yōu)解,組合全局最優(yōu)解。
第7章 圖
5 最短路徑
約定:路徑長度等于路徑中邊/弧權值之和;所有邊/弧權大于0。
5.1 單源點的最短路徑問題
59、
性質:
最短路徑由最短子路徑組成。
策略:
由近及遠計算到各頂點的最短路徑。
Edsger Dijkstra
(1930-2002)
經典之作:“GoTo Statement Considered Harmful”。
1972年因發(fā)明ALGOL語言而獲得圖靈獎,獲獎演說是“The Humble Programmer”。
在操作系統(tǒng)中,提出了PV操作;……
5.1.1 問題與對策
①如何存儲源點v到其余頂點的最短路徑長度?
vector 60、分已求解結點和未求解結點?
vector 61、選取與頂點v最近的結點w,成為已求解結點;
③借助結點w,修改從v出發(fā)到其余未求解結點的最短路徑長度;
④重復②③步驟N-1次。
案例演示
0,Inf,10,Inf,30,100;
Inf,0,5,Inf,Inf,Inf;
Inf,Inf,0,50,Inf,Inf;
Inf,Inf,Inf,0,Inf,10;
Inf,Inf,Inf,20,0,60;
Inf,Inf,Inf,Inf,Inf,0
0
1
2
3
4
5
初始化
dist
0
Inf
10
Inf
30
100
set
True
false
false
62、false
false
false
path
第一次循環(huán)后
dist
0
Inf
10
60
30
100
set
True
false
True
false
false
false
path
2
第二次循環(huán)后
dist
0
Inf
10
50
30
90
set
True
false
True
false
True
S
path
4
4
第三次循環(huán)后
dist
0
Inf
10
50
30
60
set
True
false
True 63、
True
True
false
path
4
4,3
5.1.3 算法實現一:求最短路徑長度向量
vector 64、set[j]==false && sds[w]+(*m_Es)[w][j] 65、
}
空間復雜度: O(n)
時間復雜度: O(n*n)
5.1.4 算法實現二:求最短路徑向量
vector 66、
for(int j=0; j
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
5. 裝配圖網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。