版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第8章圖
>圖的基本概念
>圖的基本運(yùn)算
A圖的基本存儲(chǔ)結(jié)構(gòu)
>圖的遍歷
A生成樹與最小生成樹
A最短路徑
A拓?fù)渑判?/p>
>關(guān)鍵路徑
8.1圖的基本概念
一、圖的定義
圖是由一個(gè)非空的頂點(diǎn)集合和一個(gè)描述頂點(diǎn)之間
多對(duì)多關(guān)系的邊(或弧)集合組成的一種數(shù)據(jù)結(jié)構(gòu),
它可以形式化地表示為:
圖=(V,E)
其中V={X|X£某個(gè)數(shù)據(jù)對(duì)象集},它是頂點(diǎn)的有窮
非空集合;E={(x,y)|x,yeV}^E={<x,y>|x,
ywV且P(x,y)},它是頂點(diǎn)之間關(guān)系的有窮集合,
也叫做邊集合,P(x,y)表示從x到y(tǒng)的一條單向
通路。
圖的應(yīng)用舉例
例1交通圖(公路、鐵路)
頂點(diǎn):地點(diǎn)
邊:連接地點(diǎn)的公路
交通圖中的有單行道雙行道,分別用有向邊、無向邊表示;
例2電路圖
頂點(diǎn):元件
邊:連接元件之間的線路
例3通訊線路圖
頂點(diǎn):地點(diǎn)
邊:地點(diǎn)間的連線
例4各種流程圖
如產(chǎn)品的生產(chǎn)流程圖
頂點(diǎn):工序
邊;客道工序之間的順序關(guān)系
通常,也將圖G的頂點(diǎn)集和邊集分別記為V(G)
和E(G)oE(G)可以是空集,若E(G)為空,
則圖G只有頂點(diǎn)而沒有邊。
若圖G中的每條邊都是有方向的,則稱G為有向
圖。在有向圖中,一條有向邊是由兩個(gè)頂點(diǎn)組成的有
序?qū)?,點(diǎn)序?qū)νǔS眉饫ㄌ?hào)表示。例如,有序?qū)Vp
多>表示一條由M到』的意向邊。有向邊又稱為弧,水
的始點(diǎn)稱為弧尾,弧的終點(diǎn)稱為弧頭。若圖G中的每
條邊都是沒有方向的,則稱G為無向圖。無向圖中的
邊均是頂點(diǎn)的無序?qū)?,無序?qū)νǔS脠A括號(hào)表示。
JO圖8-1
(VJ)----<£)(£)------殲:有序?qū)?lt;Vj,Vj>:一工
/用以為Vi起點(diǎn)、以Vj為終點(diǎn)
/51的有向線段表示,稱為有向
4)(y^)-----(O邊或弧;
(a)有向圖Gi(b)無向圖G2
圖8.1(a)表示的是有向圖G1,該圖的頂點(diǎn)集和
邊集分別為:
v
V(G1)={rv2,v3,v4}
E(G])={vvi,v2>,<vrv3>,<v2,v4>,<v3,v2>}
例:圖8"
-------<2)(vi>--------(^2)
/V:無序?qū)?Vi,Vj):
/<用連接頂點(diǎn)v「Vj的線段
?/■表示,稱為無向邊;
WWW----W.
(a)有向圖Gi(b)無向圖G2
圖8.1(b)表示的是無向圖G2,該圖的頂點(diǎn)集和
邊集分別為:
V(G2)={vrv2,v3,v4,v5}
E(G2)={(v(,v2),(v1,v3),(v1,v4),
(v2,v3),(v2,v5),(v4,v5)}
在以后的討論中,我們約定:
(1)一條邊中涉及的兩個(gè)頂點(diǎn)必須不相同,即:
若(Vj,Vj)或vv「』>是E(G)中的一條邊,則要
求中Vj;
(2)一'對(duì)頂點(diǎn)間不能有相同方向的兩條有向邊;
(3)一對(duì)頂點(diǎn)間不能有兩條無向邊,即只討論簡(jiǎn)
單的圖。
二、完全圖
若用n表示圖中頂點(diǎn)的數(shù)目,用e表示圖中邊的
數(shù)目,按照上述規(guī)定,容易得到下述結(jié)論:對(duì)于一
個(gè)具有n個(gè)頂點(diǎn)的無向圖,其邊數(shù)e小于等于n(n-1)
/2,邊數(shù)恰好等于n(n-1)/2的無向圖稱為無向完
全圖;對(duì)于一個(gè)具有n個(gè)頂點(diǎn)的有向圖,其邊數(shù)e小
于等于n(n-1),邊數(shù)恰好等于n(n-1)的有向圖
稱為有向完全圖。也就是說完全圖具有最多的邊數(shù),
任意一對(duì)頂點(diǎn)間均有邊相連。
例:圖8?2
(a)無向完全圖G3(b)有向完全圖G4
圖8.2所示的G3與分別是具有4個(gè)頂點(diǎn)的無向
完全圖和有向完全圖。圖G3共有4個(gè)頂點(diǎn)6條邊;圖
共有4個(gè)頂點(diǎn)12條邊。
若“,Vj)是一條無向邊,則稱頂點(diǎn)Vj和Vj互為
鄰接點(diǎn)。
若VVj,'>是一條有向邊,則稱Vj鄰接到Vj,¥口
接于Vj,并寐有向邊VVj,Vj>關(guān)聯(lián)于Vj與v『或稱看向
邊VVj,Vj>與頂點(diǎn)Vj和Vj相美聯(lián)。
三、度、入度、出度
在圖中,一個(gè)頂點(diǎn)的度就是與該頂點(diǎn)相關(guān)聯(lián)的
邊的數(shù)目,頂點(diǎn)v的度記為D(v)。例如在圖8.2
(a)所示的無向圖G3中,各頂點(diǎn)的度均為3。
若G為有向圖,則把以頂點(diǎn)v為終點(diǎn)的邊的數(shù)目
稱為頂點(diǎn)v的入度,記為ID(v);把以頂點(diǎn)v為始
點(diǎn)的邊的數(shù)目稱為v的出度,記為OD(v),有向
圖中頂點(diǎn)的度數(shù)等于頂點(diǎn)的入度與出度之和,即D
(v)=ID(v)+0D(v)0
無論有向圖還是無向圖,圖中的每條邊均關(guān)聯(lián)于兩
個(gè)頂點(diǎn),因此,頂點(diǎn)數(shù)n、邊數(shù)e和度數(shù)之間有如下
關(guān)系:
(式8-1)
四、子圖
給定兩個(gè)圖Gj和G『其中G產(chǎn)(M,EJ,Gp
(V『EJ,若滿足則稱Gj是Gj的
子團(tuán)。
子圖示例
(b)有向圖G4的部分子圖
五、路徑
無向圖G中若存在著一個(gè)頂點(diǎn)序列v、v;、V;、???、
55
vm\U,且(V,V;)、(V。v2)、…、(vm,U)
均屬于E(G),則稱該頂點(diǎn)序列為頂點(diǎn)v到頂點(diǎn)u的
一條路徑,相應(yīng)地,頂點(diǎn)序列II、vm\Vm」'、??.、v;、
V是頂點(diǎn)U到頂點(diǎn)V的一條路徑。
如果G是有向圖?路徑也是有向的,它由E(G)
J
中的有向邊vv,v;>、<v/,vg>、....<vm,u>組
成。路徑長(zhǎng)度是該路徑上邊或弧的數(shù)目。
如果一條路徑上除了起點(diǎn)V和終點(diǎn)U相同外,其余
頂點(diǎn)均不相同,則稱此路徑為一條簡(jiǎn)單路徑。起點(diǎn)和
終點(diǎn)相同(v=u)的簡(jiǎn)單路徑稱為簡(jiǎn)單回路或簡(jiǎn)單環(huán)。
六、連通圖與強(qiáng)連通圖
在無向圖G中,若從頂點(diǎn)寸到頂點(diǎn)Vj有路徑,貝U
稱』與凡是連通的。若V(G)中任意兩人不同的頂
點(diǎn)看和區(qū)都連通(即有路徑),則稱G為連通圖。例
如,圖8.1(b)所示的無向圖G2、圖8.2(a)所示
的無向圖G3是都是連通圖。
無向圖G的極大連通子圖稱為G的連通分量。
根據(jù)連通分量的定義,可知任何連通圖的連通分量
是其自身,非連通的無向圖有多個(gè)連通分量。
例:非連通圖及其連通分量示例
????
(a)非連通圖(b)O。的兩個(gè)連通分量H1I和H2/
在有向圖G中,若對(duì)于V(G)中任意兩個(gè)不同的
頂點(diǎn)Vj和V『都存在從Vj到Vj以及從Vj到Vj的路徑,則稱
G是強(qiáng)連通圖。
有向圖的極大強(qiáng)連通子圖稱為G的強(qiáng)連通分量。
根據(jù)強(qiáng)連通圖的定義,可知強(qiáng)連通圖的唯一強(qiáng)連通
分量是其自身,而非強(qiáng)連通的有向圖有多個(gè)強(qiáng)連分
量。例如,圖8.2(b)所示的有向圖G4是一個(gè)具有
4個(gè)頂點(diǎn)的強(qiáng)連通圖,圖8.5(a)所示的有向圖Ge
不是強(qiáng)連通圖(V2、V3.V4沒有到達(dá)的路徑),
它的兩個(gè)強(qiáng)連通分量與如圖所示。
O4+8.5(b)
(a)非強(qiáng)連通圖Ge(b)G6的兩個(gè)強(qiáng)連通分量H3和H4
七、網(wǎng)絡(luò)
有時(shí)在圖的每條邊上附上相關(guān)的數(shù)值,這種與
圖的邊相關(guān)的數(shù)值叫權(quán)。
權(quán)可以表示兩個(gè)頂點(diǎn)之間的距離、耗費(fèi)等具有
某種意義的數(shù)。若將圖的每條邊都賦上一個(gè)權(quán),則
稱這種帶權(quán)圖為網(wǎng)絡(luò)。
(a)無向網(wǎng)絡(luò)G7(b)有向網(wǎng)絡(luò)Gg
作業(yè):
8.1對(duì)于無向圖8.29,試給出
(1)圖中每個(gè)頂點(diǎn)的度;
(2)該圖的鄰接矩陣;
(4)該圖的連通分量。
圖8.29無向圖
8.2給定有向圖&30,試給出
(1)頂點(diǎn)D的入度與出度;
(2)該圖的出邊表與入邊表;
(3)該圖的強(qiáng)連通分量。
圖8.30有向圖
8.2圖的基本運(yùn)算
圖是一種復(fù)雜數(shù)據(jù)結(jié)構(gòu),由圖的定義及圖的一組基
本操作構(gòu)成了圖的抽象數(shù)據(jù)類型。
ADTGraph{
數(shù)據(jù)對(duì)象V:V是具有相同特性的數(shù)據(jù)元素的集合,稱
為頂點(diǎn)集。
數(shù)據(jù)關(guān)系R:
R={<v,w>|v,weVJLP(v,w),P(v,w)定義
了邊(或弧)(v,w)的信息}
圖的基本操作如下:
(1)creatgraph(&g)創(chuàng)建一個(gè)圖的存儲(chǔ)結(jié)構(gòu)。
(2)insertvertex(&g,v)在圖g中增加一個(gè)頂
占v
八、、VO
(3)deletevertex(&g,v)在圖g中刪除頂點(diǎn)v及
所有和頂點(diǎn)v相關(guān)聯(lián)的邊或弧。
(4)insertedge(&g,v,u)在圖g中增加一條從
頂點(diǎn)v到頂點(diǎn)u的邊或弧。
(5)deleteedge(&g,v,u)在圖g中刪除一■條從
頂點(diǎn)v到頂點(diǎn)u的邊或弧。
(6)trave(g)遍歷圖g。
(7)locatevertex(g,v)求頂點(diǎn)v在圖g中的位
序。
(8)fiirstvertex(g,v)求圖g中頂點(diǎn)v的第一個(gè)
鄰接點(diǎn)。
(9)degree(g,v)求圖g中頂點(diǎn)v的度數(shù)。
(10)nextvertex(g,v,w)求圖g中與頂點(diǎn)v相
鄰接的頂點(diǎn)w的下一個(gè)鄰接點(diǎn)。即求圖g中頂點(diǎn)v的
某個(gè)鄰接點(diǎn),它的存儲(chǔ)順序排在鄰接點(diǎn)w的存儲(chǔ)位
置之后。
}ADTGraph
8.3圖的基本存儲(chǔ)結(jié)構(gòu)
831鄰接矩陣及其實(shí)現(xiàn)
一、非網(wǎng)絡(luò)的鄰接矩陣
給定圖G=(V,E),其中V(G)={v0,
vi?Vn_J,G的鄰接矩陣(AdacencyMatrix)是
具有如下在質(zhì)的n階方陣:
「1,女口果或者
A團(tuán)力=<
[。,否則
無向圖的鄰接矩陣是對(duì)稱的,有向圖的鄰接矩
陣可能是不對(duì)稱的。
圖的鄰接矩陣示例
r0111、
1010
A1=A2=
1101
i1010;
圖8.7無向圖G9及有向圖Gw的鄰接矩陣表示
用鄰接矩陣表示圖,很容易判定任意兩個(gè)頂點(diǎn)
之間是否有邊相連,并求得各個(gè)頂點(diǎn)的度數(shù)。對(duì)于
無向圖,頂點(diǎn)V的度數(shù)是鄰接矩陣中第i行或第i列值
為1的元素個(gè)數(shù),即:
D(Vj)=區(qū)4區(qū)力=區(qū)4,口…(8-2)
7=07=0
對(duì)于有向圖,鄰接矩陣中第i行值為1的元素個(gè)
數(shù)為頂點(diǎn)Y的出度,第i列值為1的元素的個(gè)數(shù)為頂
點(diǎn)Vj的入度,即:
77—177—1
0D(vj=24,?,力;ID(Vj)=》4力].?.(8-3)
7=°7=0
二、網(wǎng)絡(luò)的鄰接矩陣
當(dāng)G=(V,E)是一個(gè)網(wǎng)絡(luò)時(shí),G的鄰接矩陣是具
有如下性質(zhì)的n階方陣:
rWy當(dāng)(v〃vj或〈吊,Vj>eE(G)
A[i,j尸<0當(dāng)(%,vj或vy,>E(G)JLi=j
00
、當(dāng)(Vj)或vvj9Vj>E(G)JLiWj
其中TV。表示邊上的權(quán)值;°°表示一個(gè)計(jì)算機(jī)允
許的、大于所有邊上權(quán)值的數(shù)。
網(wǎng)絡(luò)的鄰接矩陣示例
r0563478
0OO501
560OOOO
0OO45
34OO025
l64OO0)
I78OO250j
(a)G7的鄰接矩陣(b)G&的鄰接矩陣
圖8.8網(wǎng)絡(luò)鄰接矩陣示例
鄰接矩陣存儲(chǔ)結(jié)構(gòu)
文件名:mgraph.h
#defineFINITY5000/*此處用5000代表無窮大*/
#definem20/*最大頂點(diǎn)數(shù)*/
typedefcharvertextype;/*頂點(diǎn)值類型*/
typedefintedgetype;/*權(quán)值類型*/
typedefstruct{
vertextypevexs[m];/*頂點(diǎn)信息域*/
edgetypeedges[m][m];/*鄰接矩陣*/
intn,e;/*圖中頂點(diǎn)總數(shù)與邊數(shù)7
}mgraph;/*鄰接矩陣表示的圖類型*/
/*********************************************************/
/*圖的鄰接矩陣創(chuàng)建算法*/
/*文件名:cjjjz.c函數(shù)名:creatmgraph1()*/
/*********************************************************/
#include<stdio.h>
#include"mgraph.h1'
voidcreatmgraph1(mgraph*g)
{inti,j,k,w;/*建立有向網(wǎng)絡(luò)的鄰接矩陣存儲(chǔ)結(jié)構(gòu)*/
printf(npleaseinputnande:\n");
scanf(,'%d%d,',&g->n,&g->e);/*輸入圖的頂點(diǎn)數(shù)與邊數(shù)*/
getchar();/*取消輸入的換行符7
printf(Hpleaseinputvexs:\n");
for(i=0;i<g->n;i++)/*輸入圖中的頂點(diǎn)值*/
g->vexs[i]=getchar();
for(i=0;i<g->n;i++)/*初始化鄰接矩陣*/
for(j=0;j<g->n;j++)
if(i==j)g->edges[i]0]=O;
elseg->edges[i]O]=FINITY;
printf(npleaseinputedges:\n");
for(k=0;k<g->e;k++)/*輸入網(wǎng)絡(luò)中的邊*/
{scanf(H%d%d%d",&i,&j,&w);
g->edges[i]O]=w;
/*若是建立無向網(wǎng),只需在此力口入語句g->edges皿i]=w;即可*/
說明:
A當(dāng)建立有向網(wǎng)時(shí),邊信息以三元組(i,j,w)的形
式輸入,i、j分別表示兩頂點(diǎn)的序號(hào),w表示邊上的權(quán)。
對(duì)于每一條:俞人的邊信息(i,j,w),只需將g?
>edges[i][j]賦值為w。
A算法8.5中用到的creatmgraph2()是用于建立無向網(wǎng)
絡(luò)的函數(shù),它與creatmgraph1()向區(qū)別足于對(duì)每一條
輸入的邊信息(i,j,w),需自時(shí)將g->edges[i][j]和
g->edges[j][i]賦值為w。
?當(dāng)建立非網(wǎng)絡(luò)的存儲(chǔ)結(jié)構(gòu)時(shí),所有的邊信息只需按
二元組(i,j)的形式輸入。
832鄰接表及其實(shí)現(xiàn)
用鄰接矩陣表示法存儲(chǔ)圖,占用的存儲(chǔ)單元個(gè)
數(shù)只與圖中頂點(diǎn)的個(gè)數(shù)有關(guān),而與邊的數(shù)目無關(guān)。
一個(gè)含有n個(gè)頂點(diǎn)的圖,如果其邊數(shù)比rP少得多,
那么它的鄰接矩陣就會(huì)有很多空元素,浪費(fèi)了存儲(chǔ)
空間。
■無向圖的鄰接表
對(duì)于圖G中的每個(gè)頂點(diǎn)看,該方法把所有鄰接于Y
的頂點(diǎn)』鏈成一個(gè)帶頭結(jié)點(diǎn)的單鏈表,這個(gè)單鏈表就
稱為頂上』的鄰接表。單鏈表中的每個(gè)結(jié)點(diǎn)至少包含
兩個(gè)域,一個(gè)為鄰接點(diǎn)域(adjvex),它指示與頂點(diǎn)看
鄰接的頂點(diǎn)在圖中的位序,另一個(gè)為鏈域(next),
它指示與頂點(diǎn)Y鄰接的下一個(gè)結(jié)點(diǎn)。
在無向圖的鄰接表中,頂點(diǎn)Vj的度為第i個(gè)鏈表中
結(jié)點(diǎn)的個(gè)數(shù);而在有向圖的出邊表中,第i個(gè)鏈表中
的結(jié)點(diǎn)個(gè)數(shù)是頂點(diǎn)寸的出度;為了求入度,必須對(duì)整
個(gè)鄰接表掃描一遍,所有鏈表中其鄰接點(diǎn)域的值為i
Gm的出邊表
鄰接表的存儲(chǔ)結(jié)構(gòu)
/****************************************************I
/*鄰接表存儲(chǔ)結(jié)構(gòu)文件名:adjgraph.h*/
/****************************************************!
#definem20/*預(yù)定義圖的最大頂點(diǎn)數(shù)7
typedefchardatatype;/*頂點(diǎn)信息數(shù)據(jù)類型*/
typedefstructnode{
intadjvex;
structnode*next;
}edgenode;
typedefstructvnode{/*頭結(jié)點(diǎn)類型*/
datatypevertex;/*頂點(diǎn)信息*/
edgenode*firstedge;/*鄰接鏈表頭指針*/
Jvertexnode;
typedefstruct{/*鄰接表類型*/
vertexnodeadjlist[m];/*存放頭結(jié)點(diǎn)的順序表7
intn,e;/*圖的頂點(diǎn)數(shù)與邊數(shù)*/
Jadjgraph;
/********************************************************/
/*無向圖的鄰接表創(chuàng)建算法*/
/*文件名jljb.c函數(shù)名:createadjgraph()*/
/********************************************************/
voidcreateadjgraph(adjgraph*g)
{int
edgenode*s;
printf(nPleaseinputnande:\nn);
,
scanf("%d%d',&g->nJ&g->e);/*輸入頂點(diǎn)數(shù)與邊數(shù)*/
getchar();
printf(HPleaseinput%dvertex:n,g->n);
for(i=0;i<g->n;i++)
{scanf(tt%c,,,&g->adjlist[i].vertex);/*讀入頂點(diǎn)信息7
g->adjlist[i].firstedge=NULL;/*邊表置為空表7
)
printf("Pleaseinput%dedges:",g->e);
for(k=0;k<g->e;k++)/*循環(huán)e次建立邊表*/
{scanf("%d%d,',&i,&j);/*輸入無序?qū)?i,j)*/
s=(edgenode*)malloc(sizeof(edgenode));
s->adjvex=j;/*鄰接點(diǎn)序號(hào)為j*/
s->next=g->adjlist[i].firstedge;
g->adjlist[i].firstedge=s;/*將新結(jié)點(diǎn)*s插入頂點(diǎn)y
的邊表頭部*/
s=(edgenode*)malloc(sizeof(edgenode));
s->adjvex=i;/*鄰接點(diǎn)序號(hào)為i*/
s->next=g->adjlist[j].firstedge;
g->adjlist[j].firstedge=s;
/*將新結(jié)點(diǎn)*s插入頂點(diǎn)用的邊表頭部7
)
)
算法8.2建立無向圖的鄰接表算法
說明:一個(gè)圖的鄰接矩陣表示是唯一的,但其鄰接表
表示不唯一,這是因?yàn)樵卩徑颖斫Y(jié)構(gòu)中,各邊表結(jié)點(diǎn)
的鏈接次序取決于建立鄰接表的算法以及邊的輸入次
序。
例:若需建立下圖所示的無向圖鄰接表存儲(chǔ)結(jié)構(gòu),則
在執(zhí)行程序jljb.c時(shí)如果輸入的信息為:
45
ABCD
0102031223
則將建立如下的鄰接表存儲(chǔ)結(jié)構(gòu)。
A3-->2-->1
B2->0
C3-->1-->0
D2->0
8.3.3鄰接多重表
■在鄰接多重表中,每一條邊只有一個(gè)邊結(jié)點(diǎn)。為有關(guān)
邊的處理提供了方便。
一邊結(jié)點(diǎn)的結(jié)構(gòu)
markvexzlink:veXf\inkj
其中,mark是記錄是否處理過的標(biāo)記;vexi和
vexj是依附于該邊的兩頂點(diǎn)位置。Iniki域是鏈接指針,
指向下一條依附于頂點(diǎn)vexi的邊;Iinkj也是鏈接指針,
指向下一條依附于頂點(diǎn)vexj的邊。需要時(shí)還可設(shè)置一
個(gè)存放與該邊相關(guān)的權(quán)值的域COSto
-頂點(diǎn)結(jié)點(diǎn)的結(jié)構(gòu)
vertexFirstedge
存儲(chǔ)頂點(diǎn)信息的結(jié)點(diǎn)表以順序表方式組織,每
一個(gè)頂點(diǎn)結(jié)點(diǎn)有兩個(gè)數(shù)據(jù)成員:其中,vertex存放
與該頂點(diǎn)相關(guān)的信息,firstedge是指示第一條依
附于該頂點(diǎn)的邊的指針。
在鄰接多重表中,所有依附于同一個(gè)頂點(diǎn)的邊
都鏈接在同一個(gè)單鏈表中。
從頂點(diǎn)i出發(fā),可以循鏈找到所有依附于該頂
點(diǎn)的邊,也可以找到它的所有鄰接頂點(diǎn)。
無向網(wǎng)絡(luò)的鄰接多重表示例
其中邊表結(jié)點(diǎn)增加了一個(gè)存儲(chǔ)權(quán)值的數(shù)據(jù)域。
8.4圖的遍歷
圖的遍歷:從圖的某頂點(diǎn)出發(fā),訪問圖中所有頂點(diǎn),
并且每個(gè)頂點(diǎn)僅訪問一欠―在風(fēng)夾部分頂點(diǎn)后,
口圖的遍歷與呆證每
上一般
一個(gè)頂點(diǎn)只被訪問七述)■的遍歷有什么不匹)
用一個(gè)輔助數(shù)組為謫京衛(wèi)前;
visiJnMFT當(dāng)頂點(diǎn)vi未
被訪問,visit。]僅為0;°當(dāng)M已被訪問,則visit。]值為1。
有兩種遍歷方法(它們對(duì)無向圖,有向圖都適用)
>深度優(yōu)先遍歷
>廣度優(yōu)先遍歷
841深度優(yōu)先遍歷
從圖辯萊頌京婢度G=(V,E),首先將V中每一個(gè)頂
桿幅福靛喊z被訪問,然后,選取一個(gè)源點(diǎn)VEV,將v
標(biāo)記為,已破法泡
次撥宗v的叩有鄰祛點(diǎn)w:若w不等歷同過督7一則則似以加為
盛的春夏蜃繼續(xù)進(jìn)行深度優(yōu)先遍歷,如果從v出發(fā)有
路的頂點(diǎn)都已被訪問過,則從v的搜索過程結(jié)束。此
時(shí),如果圖中還有未被訪問過的頂點(diǎn)(該圖有多個(gè)連
通分量或強(qiáng)連通分量),則再任選一個(gè)未被訪問過的
頂點(diǎn),并從這個(gè)頂點(diǎn)開始做新的搜索。上述過程一直
進(jìn)行到V中所有頂點(diǎn)都已被訪問過為止。
例
深度優(yōu)先遍歷過程:
序列1:?
V0,V1,V3,V7,V4,V2,V5,V6
V7
由于沒有規(guī)定
訪問鄰接點(diǎn)的順序,
深度優(yōu)先序列不是唯一的
序列2:
V0,V1,V4,V7,V3,V2,V5,V6
但是,當(dāng)采用鄰接表存儲(chǔ)結(jié)構(gòu)并且存儲(chǔ)結(jié)構(gòu)已確
定的情況下,遍歷的結(jié)果將是確定的O
:CQ->c1->C3->C4-,C5->c?
采用鄰接表存儲(chǔ)結(jié)構(gòu)的深度優(yōu)先遍歷算法實(shí)現(xiàn):
/*********************************************************/
/*圖的深度優(yōu)先遍歷算法*/
/*文件名:dfs.c函數(shù)名:dfs()、dfstraverse。*/
/*********************************************************/
intvisited[m];
voiddfs(adjgraphg,inti)
{/*以%為出發(fā)點(diǎn)深度優(yōu)先遍歷頂點(diǎn)看所在的連通分量*/
edgenode*p;
printf("visitvertex:%c\n”,g.adjlist[i].vertex);/*訪問頂點(diǎn)i*/
visited[i]=1;
p=g.adjlist[i].firstedge;
while(p)/*從p的鄰接點(diǎn)出發(fā)進(jìn)行深度優(yōu)先搜索*/
{if(!visited[p->adjvex])
dfs(g,p->adjvex);/*遞歸*/
p=p->next;
)
)
voiddfstraverse(adjgraphg)
{/*深度優(yōu)先遍歷圖g7
inti;
for(i=0;i<g.n;i++)
visited[i]=O;/*初始化標(biāo)志數(shù)組*/
for(i=0;i<g.n;i++)
if(!visited[i])/*%未訪問過*/
dfs(g,i);
)
算法8.3圖的深度優(yōu)先遍歷算法(鄰接表表示法)
算法分析:
對(duì)于具有n個(gè)頂點(diǎn)和e條邊的無向圖或有向圖,遍
歷算法dfstraverse對(duì)圖中每個(gè)頂點(diǎn)至多調(diào)用一次dfs。
從dfstraverse中調(diào)用dfs或dfs內(nèi)部遞歸調(diào)用自己的最
大次數(shù)為no當(dāng)訪問某頂點(diǎn)v時(shí),dfs的時(shí)間主要耗費(fèi)
在從該頂點(diǎn)出發(fā)搜索它的所有鄰接點(diǎn)上。用鄰接表表
示圖時(shí),需搜索第i個(gè)邊表上的所有結(jié)點(diǎn),因此,對(duì)所
有n個(gè)頂點(diǎn)訪問,在鄰接表上需將邊表中所有0(e)
個(gè)結(jié)點(diǎn)檢查一遍。所以,dfstraverse算法的時(shí)間復(fù)雜
度為O(n+e)o
842廣度優(yōu)先遍歷
圖中某未訪問過的頂點(diǎn)M出發(fā):
1)訪問頂點(diǎn)、M;
2)訪問Vj的所有未被訪問的鄰接點(diǎn)叫,w2,...wk;
3)依次從這些鄰接點(diǎn)出發(fā),訪問它們的所有未被訪問
的鄰接點(diǎn);依此類推,直到圖中所有訪問過的頂點(diǎn)的
鄰接點(diǎn)都被訪問;
求圖G的以Vo起點(diǎn)的的廣度??
優(yōu)先序列....
V0,V1,V2,V3,V4,V5,V6,V7?
c
從Co出發(fā)的BFS序列為:
cc
CQ—>C1一>C2—>C3—>一>
c
cc
由于沒有規(guī)定
訪問鄰接點(diǎn)的順序,
廣度優(yōu)先序列不是唯一的
廣度優(yōu)先算法:
從圖中某頂點(diǎn)vi出發(fā):
1)訪問頂點(diǎn)vi;(容易實(shí)現(xiàn))
2)訪問vi的所有未被訪問的鄰接點(diǎn),w2,...wk;
3)依次從這些鄰接點(diǎn)(在步驟2)訪問的頂點(diǎn))出
發(fā),訪問它們的所有未被訪問的鄰接點(diǎn);依此類推,
直到圖中所有訪問過的頂點(diǎn)的鄰接點(diǎn)都被訪問;
為實(shí)現(xiàn)3),需要保存在步騁。、出公間的頂點(diǎn),而
且訪問這些頂點(diǎn)鄰》在廣度優(yōu)先遍歷算法中,
其鄰接點(diǎn)先被說需設(shè)置一隊(duì)列Q,
保存已訪問的頂點(diǎn),
并控制遍歷頂點(diǎn)的順序。
QUEUE
數(shù)據(jù)結(jié)構(gòu):
1)全局標(biāo)志數(shù)組
intvisited[m];/*全局標(biāo)志向量*/
2)鄰接表存儲(chǔ)結(jié)構(gòu)
/******************************************************/
/*圖的廣度優(yōu)先遍歷算法7
/*程序名bfs.c函數(shù)名bfs()、bfstraverse()*/
/******************************************************/
voidbfs(adjgraphg,inti)
{intj;/*從頂點(diǎn)i出發(fā)廣度優(yōu)先遍歷頂點(diǎn)i所在的連通分量*/
edgenode*p;
intqueue[20],head,tail;"FIFO隊(duì)列*/
head=-1;tail=-1;/*初始化空隊(duì)列7
printf(”%c,',g.adjlist[i].vertex);/*訪問源點(diǎn)v*/
visited[i]=1;
queue[++tail]=i;/*被訪問結(jié)點(diǎn)進(jìn)隊(duì)*/
while(tail>head)/*當(dāng)隊(duì)列非空時(shí),執(zhí)行下列循環(huán)體*/
{j=queue[++head];/*出隊(duì)*/
p=g.adjlistO].firstedge;
while(p)/*廣度優(yōu)先搜索鄰接表*/
{if(visited[p->adjvex]==O)
{printf(H%c",g.adjlist[p->adjvex].vertex);
queue[++tail]=p->adjvex;
visited[p->adjvex]=1;
)
p=p->next;
)
})
intbfstraverse(adjgraphg,datatypev)
{inti,count=0;/*廣度優(yōu)先遍歷圖g*/
for(i=0;i<g.n;i++)visited[i]=O;/*初始化標(biāo)志數(shù)組7
i=loc(g,v);/*尋找頂點(diǎn)v在鄰接表中的位序7
if(i!=-1)
{count++;/*連通分量個(gè)數(shù)加1*/
bfs(g,i);
)
for(i=0;i<g.n;i++)
if(!visited[i])/%未訪問過*/
{printf(”\n”);
count++;/*連通分量個(gè)數(shù)加1*/
bfs(g,i);/*從頂點(diǎn)i出發(fā)廣度優(yōu)先遍歷圖g*/
)
returncount;/*返回?zé)o向圖g中連通分量的個(gè)數(shù)7
算法8.4圖的廣度優(yōu)先遍歷算法(鄰接表表示法)
算法的時(shí)間復(fù)雜度與深度優(yōu)先算法相同O
作業(yè):
8.4圖8.31是某個(gè)無向圖的鄰接表,請(qǐng)
(1)畫出此圖;
(2)寫出從頂點(diǎn)A開始的DFS遍歷結(jié)果。
(3)寫出從頂點(diǎn)A開始的BFS遍歷結(jié)果。
8.5生成樹與最小生成樹
對(duì)于一個(gè)無向的連通圖6=(V,E),設(shè)G'是
它的一個(gè)子圖,如果G,中包含了G中所有的頂點(diǎn)
(即V(G')=V(G))且G'是無回路的連通圖,
則稱G,為G一棵的生成樹。
深度優(yōu)先生成樹:按深度優(yōu)先遍歷生成的生成樹
廣度優(yōu)先生成樹:按廣度優(yōu)先遍歷生成的生成樹
有向圖的生成樹
851最小生成樹的定義
若有一個(gè)連通的無向圖G,有n個(gè)頂點(diǎn),并且
它的邊是有權(quán)值的。在G上構(gòu)造生成樹G',使這n?1
條邊的權(quán)值之和在所有的生成樹中最小。
要在n個(gè)城市間建立交通
網(wǎng),要考慮的問題如何在保
證n點(diǎn)連通的前題下最節(jié)省
經(jīng)費(fèi)?
上述問題即要使得生成樹各用(T)=W-
邊權(quán)值之各最小,即:
構(gòu)造最小生成樹的準(zhǔn)則:
A必須只使用該網(wǎng)絡(luò)中的邊來構(gòu)造最小生成樹;
A必須使用且僅使用nT條邊來聯(lián)接網(wǎng)絡(luò)中的n個(gè)頂點(diǎn);
A不能使用產(chǎn)生回路的邊。
MST性質(zhì):
假設(shè)G=(V,E)是一個(gè)連通網(wǎng),U是頂點(diǎn)集V的
一個(gè)非空真子集,若(u,v)是滿足UEU,vwV.U的
邊(稱這種邊為兩棲邊)且(u,V)在所有的兩棲
邊中具有最小的權(quán)值(此時(shí),稱(II,V)為最小兩
棲邊),則必存在一棵包含邊(u,V)的最小生成
樹。
必存在另一條邊(U:V'),其中U'eU,V'eV
(Prim)算法和(Kruskal)算法是兩個(gè)利用MST性質(zhì)
構(gòu)造最小生成樹的算法。
8.5.2最小生成樹的普里姆算法
■普里姆算法的基本思想:
從連通網(wǎng)絡(luò)}中的某一頂點(diǎn)出
G={V,Eu0
發(fā),選擇與它關(guān)聯(lián)的具有最小權(quán)值的邊(Uo,v),將
其頂點(diǎn)加入到生成樹的頂點(diǎn)集合U中。
以后每一'步從一個(gè)頂點(diǎn)在U中,而另一'個(gè)頂點(diǎn)不
在U中的各條邊中選擇權(quán)值最小的邊(u,v),把它的頂
點(diǎn)加入到集合U中。如此繼續(xù)下去,直到網(wǎng)絡(luò)中的所
有頂點(diǎn)都加入到生成樹頂點(diǎn)集合U中為止。
Prim算法的基本步驟如下:
(1)初始化:U={u。},TREE={};
(2)如果U=V(G),則輸出最小生成樹T,并結(jié)
束算法;
(3)在所有兩棲邊中找一條權(quán)最小的邊(u,v)
(若候選兩棲邊中的最小邊不止一條,可任選其中
的一條),將邊(u,v)加入到邊集TREE中,并將
頂點(diǎn)v并入集合U中。
(4)由于新頂點(diǎn)的加入,U的狀態(tài)發(fā)生變化,需要
對(duì)U與V-U之間的兩棲邊進(jìn)行調(diào)整。
(5)轉(zhuǎn)步驟(2)
5
10
(a)無向網(wǎng)(b)初始狀態(tài)(c)選取(A、B)(d)選取(B、D
(e)選取(B、F)(f)選取(B、C)(g)選取(E、F)
Prim算法實(shí)現(xiàn):
1、連通圖用鄰接矩陣net表示:
(Wjj當(dāng)(vi,vj)eE(G)且權(quán)為Wu
當(dāng)上可
edges[i][j]=10
OO否則
2、邊tree(生成樹)edgetree[n-l]
typedefstructedgedata
{intbeg,en;/*beg,en是結(jié)點(diǎn)序號(hào)*/
intlength;/*邊長(zhǎng)*/
}edge;
Prim算法構(gòu)造最小生成樹的過程
tree01234
Ibeg|00000
12345
〔length1012001500
(a)初始態(tài)K=0m=l
tree01234
IbegI00000
12345
〔length1012001500
(b)最小兩棲邊(0,1)K=0
bego__i__i__
en_____1__3__2__4__5
length1057156
(d)最小兩棲邊(L5K=2
tree01234
begI0I1I1I5FT"
en____1__3__5__42
length10561c)7
(e)最小兩棲邊(L2)N6:3
tree01234
begI0I1I1I1I5
en____1__3__5__24
length1056__710
(f)tree中存儲(chǔ)了最小生成樹的邊
算法關(guān)鍵一步:求第k條輕邊,將其加入tree中
1)求當(dāng)前最小兩棲邊及應(yīng)添加的點(diǎn)v
min=tree[k].length;
s=k;
for(j=k+1;j<=g.n-2;j++)
if(treeO].length<min)
{min=treeO].length;
s=j;
)
v=tree[s].en;/*入選頂點(diǎn)為v*/
2)通過交換,將當(dāng)前輕邊加入tree中
x=tree[s];tree[s]=tree[k];tree[k]=x;
3)調(diào)整各剩余點(diǎn)對(duì)應(yīng)的最小兩棲邊(由V力口入弓|起)
for(j=k+1;j<=g.n-2;j++)
{d=g.edges[v][tree[j].en];
if(d<treeO].length)
{tree[j].length=d;
treeO].beg=v;
)
}
算法總體控制:
1)初始化:建立初始入選點(diǎn),并初始化生成樹邊
集tree。
for(v=1;v<=g.n-1;v++)
{tree[v-1].beg=0;/*此處從頂點(diǎn)v0開始求最小生成樹*/
tree[v-1].en=v;
tree[v-1].length=g.edges[0][v];
)
2)依次求當(dāng)前最小兩棲邊,并將其加入tree
for(k=0;k<=g.n-3;k++)執(zhí)彳亍關(guān)鍵一步
程序演示:prim.c
一般來講,
由于普里姆算法的時(shí)間復(fù)雜度為0(己),則適于
稠密圖。
853最小生成樹的克魯斯卡爾算法
Kruskal算法基本思想:
為使生成樹上邊的權(quán)值之和最小,顯然,其中
每一條邊的權(quán)值應(yīng)該盡可能地小??唆斔箍査惴?/p>
的做法就是:先構(gòu)造一個(gè)只含n個(gè)頂點(diǎn)的子圖SG,
然后從權(quán)值最小的邊開始,若它的添加不使SG中
產(chǎn)生回路,則在SG上加上這條邊,如此重復(fù),直
至加上n-1條邊為止。
克魯斯卡爾算法需對(duì)e條邊按權(quán)值進(jìn)行排序,其時(shí)
間復(fù)雜度為O(eloge),則適于稀疏圖。
算法:
(1)初始化,TV={V。,%,...,vn}?TE={};
(2)如果TE具有n-1條邊,則輸出最小生成樹T,
并結(jié)束算法。
(3)在有序的E(G)邊表序列中,從當(dāng)前位置向
后尋找滿足下面條件的一條邊(U,V):使得U在
一個(gè)連通分量上,V在另一個(gè)連通分量上,即(U,
v)是滿足此條件權(quán)值最小的邊,將其加入到T中,
合并U與V所點(diǎn)的兩個(gè)連通分量為一個(gè)連通分量。
(4)轉(zhuǎn)(2)
Kruskal算法動(dòng)態(tài)演示:
(a)無向網(wǎng)絡(luò)圖(b)最小生成樹求解過程
Kruskal算法構(gòu)造最小生成樹的過程
(a)
(d)(e)
/*********************************************/
/*kruskal求解最小生成樹算法*/
/*文件名kruskal.c函數(shù)名kruskal。7
/*********************************************/
voidkruskal(edgeadjlist[],edgetree[],intcnvx[],intn)
{intv=O,j,k;
forG=O;j<n;j++)
cnvx[j]=j;/*設(shè)置每一個(gè)頂點(diǎn)的連通分量*/
for(k=0;k<n-1;k++)/*樹中共有條邊7
{while(cnvx[adjlist[v].beg]==cnvx[adjlist[v].en])v++;
/*找到屬于兩個(gè)連通分量權(quán)最小的邊*/
tree[k]=adjlist[v];/*將邊v加入到生成樹中*/
for0=O;j<n;j++)/*兩個(gè)連通分量合并為一個(gè)連通分量7
if(cnvx[j]==cnvx[adjlist[v].en])
cnvx[j]=cnvx[adjlist[v].beg];
v++;
)
printf("最小生成樹是:\n");
for(j=O;j<n-1;j++)
printf(,,%3d%3d%6d\n',,tree0].beg,tree[j].en,tree[j].length);
}
算法8.6Kruskal求解最小生成樹
8.6最短路徑
問題的提出:
交通咨詢系統(tǒng)、通訊網(wǎng)、計(jì)算機(jī)網(wǎng)絡(luò)常要尋找兩結(jié)點(diǎn)
間最短路徑;
交通咨詢系統(tǒng):A到B最短路徑;
計(jì)算機(jī)網(wǎng)絡(luò):發(fā)送Email節(jié)省費(fèi)用A到B沿最短路徑
傳送;
路徑長(zhǎng)度:路徑上邊數(shù)
路徑上邊的權(quán)值之和
最短路徑:兩結(jié)點(diǎn)間權(quán)值之和最小的路徑;
始點(diǎn)最短路徑路徑長(zhǎng)度
10
如何求從某源點(diǎn)
到其余各點(diǎn)的最短路徑?
oO
本節(jié)介紹求最短路徑的兩個(gè)算法
A求從某個(gè)源點(diǎn)到其他各頂點(diǎn)的最短路徑(單源最短
路徑)。
?求每一對(duì)頂點(diǎn)之間的最短路徑。
861單源最短路徑
單源最短路徑問題是指:對(duì)于給定的有向網(wǎng)G=(V,
E),求源點(diǎn)V。到其它頂點(diǎn)的最短路徑。
Dijkstra提出了一個(gè)按路徑長(zhǎng)度遞增的順序逐步產(chǎn)生
最短路徑的方法,稱為Dijkstra算法。
Dijkstra算法的基本思想:
把圖中所有頂點(diǎn)分成兩組,第一組包括已確定最短
路徑的頂點(diǎn),初始時(shí)只含有一個(gè)源點(diǎn),記為集合S;
第二組包括尚未確定最短路徑的頂點(diǎn),記為V-S。按
最短路徑長(zhǎng)度遞增的順序逐個(gè)把V?S中的頂點(diǎn)加到S中
去,直至從v0出發(fā)可以到達(dá)的所有頂點(diǎn)都包括到S中。
在這個(gè)過程中,總保持從V。到第一組(S)各頂點(diǎn)的
最短路徑都不大于從V。到第二組(V?S)的任何頂點(diǎn)的
最短路徑長(zhǎng)度,第二組的頂點(diǎn)對(duì)應(yīng)的距離值是從V。到
此頂點(diǎn)的只包括第一組(S)的頂點(diǎn)為中間頂點(diǎn)的最
短路徑長(zhǎng)度。對(duì)于S中任意一點(diǎn)j,V。到j(luò)的路徑長(zhǎng)度皆
小于V。到(V6)中任意一點(diǎn)的路徑長(zhǎng)度。
■引入一個(gè)輔助數(shù)組d[]。它的每一個(gè)分量d[i]表示當(dāng)前
找到的從源點(diǎn)V。到頂點(diǎn)Vj的最短路徑的長(zhǎng)版。初始狀
態(tài):
-若從源點(diǎn)V。到頂點(diǎn)Vj有邊,貝[□為該邊上的權(quán)值
-若從源點(diǎn)v0到頂點(diǎn)y沒有邊,則d[i]為+ooo
■一般情況下,假設(shè)S是已求得的最短路徑的終點(diǎn)的集
合,則可證明:下一條最短路徑必然是從出發(fā),中
間只經(jīng)過S中的頂點(diǎn)便可到達(dá)的那還頂點(diǎn)V-s
)的珞徑中的二條二...............................
■每茨求得二條最短路徑之后,其終點(diǎn)丫卜加入集合S,
然后對(duì)所有的MeV-S,修改其d[i]值。
Dijkstra算法可描述如下:
1)初始化:把圖中的所有頂點(diǎn)分成兩組;初始化源
點(diǎn)到各點(diǎn)的距離向量。
fS:已確定最短路徑的點(diǎn)集,初始S-{v};
<__0
Is":尚未確定最短路徑的點(diǎn)集,初始W-V(G)-V。;
d[j]—g.edges[v0][j],j=1,2,…,n-1;
//n為圖中頂點(diǎn)個(gè)數(shù)
2)求出S與5間的最短路徑,及相應(yīng)的點(diǎn)V
d[v]-min{d[i]},ieV(G)-S;
S-SU{v};
ss
3)由于v的加入,修改S中各結(jié)點(diǎn)與5中各點(diǎn)的最短
距離:
d[i]_min<d[i],d[v]+edges[v][i]},
對(duì)于每一個(gè)i£V-S;
4)判斷:若S=V,則算法結(jié)束,否則轉(zhuǎn)2)o
Dijkstra算法中各輔助數(shù)組的變化
距離向量d路徑向量p
循環(huán)集合SV
012345012345
初始化僅}—0004280000—1-100-1—1
1IAC120194280012T200T2
2{ACF150194253012-120552
;3(ACFB110194252912T20512
4{ACFBD130194252912-120512
5{ACFBDE140194252912T20512
如何從表中讀取源點(diǎn)0到終點(diǎn)v
的最短路徑?例如頂點(diǎn)A到D的最
短距離是d[3]=25,根據(jù)p[3]=5
一p[5]=2一p[2]=0,反過來排
列,得到路徑0,2,5,3(即A、C
、F、D)。
算法實(shí)現(xiàn)如下:
/***************************************************/
/*單源最短路徑算法文件名:dijkstra.c*1
/*函數(shù)名:spath_dij()、print_gpd()*/
/***************************************************/
includenc_ljjz.c"/*引入鄰接矩陣創(chuàng)建程序*/
typedefenum{FALSE,TRUE}boolean;"false為0,true為1*/
typedefintdist[m];/*距離向量類型*/
typedefintpath[m];/*路徑向量類型*/
voidspath_dij(mgraphg,intvO.pathp,distd)
{booleanfinal[m];
inti,kj,v,min,x;
/*第1步初始化集合S與距離向量d7
for(v=0;v<g.n;v++)
{final[v]=FALSE;
d[v]=g.edges[vO][v];
if(d[v]<FINITY&&d[v]!=0)p[v]=vO;elsep[v]=-1;
/*v無前驅(qū)*/
)
final[vO]=TRUE;d[v0]=0;/*初始時(shí)s中只有一個(gè)頂點(diǎn)7
/*第2步依次找出n?1個(gè)結(jié)點(diǎn)加入S中*/
for(i=1;i<g.n;i++)
{min=FINITY;
for(k=0;kvg.n;++k)/*找最小邊及對(duì)應(yīng)的入選頂點(diǎn)*/
if(!final[k]&&d[k]<min){v=k;min=d[k];}/*!final[k]表示k還
在V-S中*/
printf("\n%c—%d\n",g.vexs[v],min);/*輸出本次入
選的頂點(diǎn)及距離7
if(min==FINITY)return;
final[v]=TRUE;/*V力口入S*/
/*第3步修改S與V-S中各結(jié)點(diǎn)的距離7
for(k=0;k<g.n;++k)
if(!final[k]&&(min+g.edges[v][k]<d[k]))
{d[k]=min+g.edges[v][k];
P[k]=v;}
}/*endfor*/
voidprint_gpd(mgraphg,pathp,distd)
{/*輸出有向圖的最短路徑7
intst[20],i,pre,top=-1;/*定義棧st并初始化空棧7
for(i=0;i<g.n;i++)
{printf(”\nDistancd:%7d,path:1',d[i]);
st[++top]=i;
pre=p[i];/*從第i個(gè)頂點(diǎn)開始向前搜索最短路徑上的頂點(diǎn)*/
while(pre!=-1)
{st[++top]=pre;
pre=p[pre];}
while(top>0)
printf(,'%2d,',st[top-]);}}
voidmain()/*主程序7
{mgraphg;/*有向圖7
pathp;/*路徑向量*/
distd;/*最短路徑向量7
intvO;
creatmgraph1(&g);/*創(chuàng)建有向網(wǎng)的鄰接矩陣*/
print(g);/*輸出圖的鄰接矩陣7
printf(npleaseinputthesourcepointvO:1');
scanf(”%d”,&vO);/*輸入源點(diǎn)*/
spath_dij(g,vO,p,d);/*求vO至U其他各點(diǎn)的最短距離*/
print_gpd(g,pJd);/*輸出V0到其它各點(diǎn)的路徑信息及距離*/
862所有頂點(diǎn)對(duì)的最短路徑
■問題的提法:已知一個(gè)各邊權(quán)值均大于0的帶權(quán)有
向圖,對(duì)每一對(duì)頂點(diǎn)viwvj,要求求出vi與vj之
間的最短路徑和最短路徑長(zhǎng)度。
解決這個(gè)問題顯然可以利用單源最短路徑算法,
具體做法是依次把有向網(wǎng)G中的每個(gè)頂點(diǎn)作為源點(diǎn)
,重復(fù)執(zhí)行Dijkstra算法n次,即靈行循環(huán)體:總的
時(shí)間復(fù)雜度為0(n3)。
for(v=0;v<g,n;v++)
(spath_dij(g,v,p,d);
prinjgpd(g,p,d);
下面將介紹用弗洛伊德(Floyd)算法來實(shí)現(xiàn)此功
能,時(shí)間復(fù)雜度仍為0(n3),但該方法比調(diào)用n次迪杰斯
特拉方法更直觀一'些。
2.弗洛伊德算法的基本思想
弗洛伊德算法仍然使用前面定義的圖的鄰接矩陣
edges[N][N]來存儲(chǔ)帶權(quán)有向圖。算法的基本思想是:
設(shè)置一個(gè)NxN的矩陣A[N][N],其中除對(duì)角線的元
素都等于0外,其它元素的值表示頂點(diǎn)i到頂點(diǎn)j的
最短路徑長(zhǎng)度,運(yùn)算步驟為:
開始時(shí),以任意兩個(gè)頂點(diǎn)之間的有向邊的權(quán)值作
為路徑長(zhǎng)度,沒有有向邊時(shí),路徑長(zhǎng)度為巴此時(shí),A
[i]0]=edges[i]0],
以后逐步嘗試在原路徑中加入其它頂點(diǎn)作為中
間頂點(diǎn),如果增加中間頂點(diǎn)后,得到的路徑比原來
的路徑長(zhǎng)度減少了,則以此新路徑代替原路徑,修
改矩陣元素。具體做法為:
第一步,讓所有邊上加入中間頂點(diǎn)0,取A[i]0]與
A[i][0]+A[0][j]中較小的值作的值.
第二步,讓所有邊上加入中間頂點(diǎn)1,取與
中較小的值,完成后得到…,如此
進(jìn)行下去,當(dāng)?shù)趎步完成后,得到,即為我們所
求結(jié)果,A表示頂點(diǎn)i到頂點(diǎn)j的最短距離。
因此,弗洛伊德算法可以描述為:
'A(-1)[i]|j]=edges[i]O];"edges為圖的鄰接矩陣*/
<
<A(k+1)[i][j]=min{Ak[i][j],Ak[i][k+1]+Ak[k+1][j]}
其中k=-1,1,2,...,n-2
下面給出Floyd的算法實(shí)現(xiàn)。
/*************************************************/
/*Floyd所有頂點(diǎn)對(duì)最短路徑算法7
/*文件名:floyd.c函數(shù)名:floyd1()*/
/*************************************************/
typedefintdist[m][m];/*距離向量*/
typedefintpath[m][m];/*路徑向量*/
voidfloyd1(mgraphg,pathp,distd)
{inti,j,k;
for(i=0;i<g.n;i++)/*初始化*/
for0=O;j<g.n;j++)
{d[i]0]=g-edges[i]0];
if(i!=j&&d[i]O]<FINITY)p[i]O]=i;elsep[i]0]=-1;
for(k=0;k<g.n;k++)/*遞推求解每一對(duì)頂點(diǎn)間的最短距離*/
{for(i=0;i<g.n;i++)
for0=O;j<g.n;j++)
if(d[i]0]>(d[i][k]+d[k]0]))
{d[i]0]=d[i][k]+d[k]0];
P[i]Ul=k;
)
)
算法8.8求網(wǎng)絡(luò)中每一對(duì)頂點(diǎn)之間的最短路徑
例
求下圖中所在頂點(diǎn)對(duì)之間的最短路徑。
rO1OO41
OO092
3508
0」
OOOO6
8.7拓?fù)渑判?/p>
一AOV網(wǎng)
有向無環(huán)圖:沒有回路的有向圖
應(yīng)用:工程流程、生產(chǎn)過程中各道工序的流程、程序
流程、課程的流程。
AOV網(wǎng)(activityonvertexnet)
用頂點(diǎn)表示活動(dòng),邊表示活動(dòng)的順序關(guān)系的有向圖
稱為AOV網(wǎng)。
某工程可分為7個(gè)子工程,若用頂點(diǎn)表示子工程(
也稱活動(dòng)),用弧表示子工程間的順序關(guān)系。工程流
程可用如下AOV網(wǎng)表示
二AOV網(wǎng)與拓?fù)渑判?/p>
A拓?fù)渑判?/p>
對(duì)工程問題,人們至少關(guān)心如下兩類問題:
1)工程能否順序進(jìn)行,即工程流程是否“合理”?
2)完成整項(xiàng)工程至少需要多少時(shí)間,哪些子工程是影臉
工程進(jìn)度的關(guān)鍵子工程?
為求解工程流程是否“合理”,通常用AOV網(wǎng)的
有向圖展示工程流程。
例1某工程可分為V。、Vv、2、、3、、4、、5、V67
個(gè)子工程,工程流程可用如下AOV網(wǎng)表示。其中頂點(diǎn)
:表示子工程(也稱活動(dòng)),?。罕硎咀庸こ涕g的
順序關(guān)系。
例課程流程圖
某校計(jì)算機(jī)專業(yè)課程流程可AOV網(wǎng)表示。其中頂點(diǎn):
表示課程(也稱
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 個(gè)人搬家服務(wù)2024年度合同3篇
- 二零二五版KTV消防安全檢查與整改服務(wù)合同2篇
- 二零二五年方管產(chǎn)品綠色包裝設(shè)計(jì)與實(shí)施合同3篇
- 2024年高端定制家具制造合同
- 2024無人機(jī)航拍與監(jiān)測(cè)服務(wù)合同
- 二零二五版歷史文化名城保護(hù)項(xiàng)目技術(shù)咨詢合同3篇
- 二零二五版廢鐵回收處理與環(huán)保服務(wù)合同3篇
- 2024年薪資隱私協(xié)議3篇
- 二零二五年白酒質(zhì)量檢測(cè)與認(rèn)證服務(wù)合同2篇
- 武漢華夏理工學(xué)院《世界音樂文化》2023-2024學(xué)年第一學(xué)期期末試卷
- 2023年中考語文備考之名著閱讀《經(jīng)典常談》思維導(dǎo)圖合集
- 2023年湘教版數(shù)學(xué)七年級(jí)下冊(cè)《整式的乘法》單元質(zhì)量檢測(cè)(含答案)
- 氣柜安裝工程施工方案
- GB/T 28750-2012節(jié)能量測(cè)量和驗(yàn)證技術(shù)通則
- GB/T 18791-2002電子和電氣陶瓷性能試驗(yàn)方法
- 分子生物學(xué)本基因組及基因組學(xué)概論
- 《人工智能》全冊(cè)配套課件
- 統(tǒng)編部編版四年級(jí)道德與法治下冊(cè)優(yōu)秀課件【全冊(cè)】
- 高職大?!扼w育與健康》課程標(biāo)準(zhǔn)
- 12月1日世界艾滋病日預(yù)防艾滋病講座PPT珍愛生命預(yù)防艾滋病PPT課件(帶內(nèi)容)
- 測(cè)量?jī)x器自檢記錄表(全站儀)
評(píng)論
0/150
提交評(píng)論