圖的定義與術(shù)語
1、圖按照有無方向分為無向圖和有向圖。無向圖由頂點和邊構(gòu)成,有向圖由頂點和弧構(gòu)成。弧有弧尾和弧頭之分。
2、如果任意兩個頂點之間都存在邊叫完全圖,有向的叫有向完全圖。若無重復(fù)的邊或頂點到自身的邊則叫簡單圖。
3、圖中頂點之間有鄰接點、依附的概念。無向圖頂點的邊數(shù)叫做度,有向圖頂點分為入度和出度。
4、圖上的邊或弧上帶權(quán)則稱為網(wǎng)。
5、圖中頂點間存在路徑,兩頂點存在路徑則說明是連通的,如果路徑最終回到起始點則稱為環(huán),當(dāng)中不重復(fù)叫簡單路徑。若任意兩頂點都是連通的,則圖就是連通圖,有向則稱為強(qiáng)連通圖。
6、無向圖中連通且n個頂點n-1條邊叫生成樹。有向圖中一頂點入度為0其余頂點入度為1的叫有向樹。
圖的存儲結(jié)構(gòu)
鄰接矩陣
圖的鄰接矩陣存儲方式是用兩個數(shù)組來表示圖。一個一維數(shù)組存儲圖中頂點信息,一個二維數(shù)組存儲圖中的邊或弧的信息。
鄰接矩陣存儲的結(jié)構(gòu)代碼如下:
typedef? char VertexType;/*頂點類型應(yīng)由用戶定義*/
typedef int? EdgeType;/*邊上的權(quán)值類型應(yīng)由用戶定義*/
#define MAXVEX? 100//最大頂點數(shù),由用戶定義
#define INFINITY? 65535//用65535來代表無限
typedef struct {
???? VertexType vexs[MAXVEX];//頂點表
???? EdgeType arc[MAXVEX][MAXVEX];//鄰接矩陣,可看作邊表
???? int? numVertexes, numEdges;//圖中當(dāng)前的頂點數(shù)和邊數(shù)
}MGraph;
/*建立無向網(wǎng)圖的鄰接矩陣表示*/
void CreateMGraph(MGraph *G) {
??? int i,j,k,w;
??? printf("輸入頂點數(shù)和邊數(shù):\n");
??? scanf("%d,%d",&G->numVertexes,&G->numEdges);/*輸入頂點數(shù)和邊數(shù)*/
??? for(i=0;i<G->numVertexes;i++)/*讀入頂點信息,建立頂點表*/
????????? scanf(&G->vexs[i]);
??? for(i=0;i<G->numVertexes;i++)
?????????? for(j=0;j<G->numVertexes;j++)
???????????????????? G->arc[i][j]=INFINITY;/*鄰接矩陣初始化*/
???? for(k=0;k<G->numEdges;k++)/*讀入numEdges條邊,建立鄰接矩陣*/
???? {
??????????? printf("輸入邊(vi,vj)上的下標(biāo)i,小標(biāo)j和權(quán)w:\n");
???????????? scanf("%d,%d,%d",&i,&j,&w);/*輸入邊(vi,vj)上的權(quán)w*/
??????????? G->arc[i][j]=w;
??????????? G->arc[j][i] =G->arc[i][j];/*因為是無向圖,矩陣對稱*/
?????? }
}
鄰接表
鄰接表存儲方法:
1、圖中頂點用一維數(shù)組存儲,每個數(shù)據(jù)元素存儲指向第一個鄰接點的指針,以便于查找該頂點的邊信息。
2、圖中每個頂點vi的所有鄰接點構(gòu)成一個線性表,由于鄰接點的個數(shù)不定,所以用單鏈表存儲,無向圖稱為頂點vi的邊表,有向圖則稱為頂點vi作為弧尾的出邊表。
結(jié)點定義代碼:
typedef char? VertexType;/*頂點類型應(yīng)由用戶定義*/
typedef? int EdgeType;/*邊上的權(quán)值類型應(yīng)由用戶定義*/
typedef? struct? EdgeNode/*邊表結(jié)點*/
{
??? int adjvex;???????????????????????? /*鄰接點域,存儲該頂點對應(yīng)下標(biāo)*/??? EdgeType? weight;?????????? /*用于存儲權(quán)值,對于非網(wǎng)圖可以不需要*/
??? struct? EdgeNode *next; /*鏈域,指向下一個鄰接點*/
}EdgeNode;
typedef struct VertexNode/*頂點表結(jié)點*/
{
???? VertexType data;?????????? /*頂點域,存儲頂點信息*/???? EdgeNode? *firstedge;/*邊表頭指針*/
}VertexNode,AdjList[MAXVEX];
typedef? struct{
???? AdjList adjList;
???? int? numVertexes,numEdges;??? /*圖中當(dāng)前頂點數(shù)和邊數(shù)*/
}GraphAdjList;
無向圖鄰接表創(chuàng)建代碼:
/*建立圖的鄰接表結(jié)構(gòu)*/
void? CreateALGraph(GraphAdjList *G) {
???? int i,j,k;
???? EdgeNode? *e;
???? printf("輸入頂點數(shù)和邊數(shù):\n");
????? scanf("%d,%d",&G->numVertexes,&G->numEdges);/*輸入頂點數(shù)和邊數(shù)*/
????? for(i = 0; i < G->numVertexes;i++)/*讀入頂點信息,建立頂點表*/
?????? {
????????????????? scanf(&G->adjList[i].data);/*輸入頂點信息*/
????????????????? G->adjList[i].firstedge=NULL;/*將邊表置空*/
???????? }
??????? for(k = 0; k < G->numEdges;k++) {/*建立邊表*/
??????????????? printf("輸入邊(vi,vj)上的頂點序號:\n");
???????????????? scanf("%d,%d",&i, &j);/*輸入邊(vi,vj)上的頂點序號*/
???????????????? e=(EdgeNode*)malloc(sizeof(EdgeNode));/*向內(nèi)存申請空間,生成邊表結(jié)點*/
???????????????? e->adjvex=j;/*鄰接序號為j*/
???????????????? e->next=G->adjList[i].firstedge;/*將e指針指向當(dāng)前頂點指向的結(jié)點*/
???????????????? G->adjList[i].firstedge=e;/*將當(dāng)前頂點的指針指向e*/
???????????????? e=(EdgeNode*)malloc(sizeof(EdgeNode));/*向內(nèi)存申請空間,生成邊表結(jié)點*/
????????????????? e->adjvex=i;
???????????????? e->next=G->adjList[j].firstedge;/*將e指針指向當(dāng)前頂點指向的結(jié)點*/
???????????????? G->adjList[j].firstedge=e;/*將當(dāng)前頂點的指針指向e*/
?????????? }
}
剩余的圖的存儲結(jié)構(gòu)還有,十字鏈表,鄰接多重表,邊集數(shù)組。
圖的遍歷
深度優(yōu)先遍歷
//鄰接矩陣的深度優(yōu)先遍歷
typedef int Boolean;? /*Boolean是布爾類型,其值是TRUE或FALSE*/
Boolean visited[MAX];/*訪問標(biāo)志的數(shù)組*/
/*鄰接矩陣的深度優(yōu)先遞歸算法*/
void DFS(MGraph G, int i) {
? ? int j;
? ? visited[i] = TRUE;
? ? printf("%c", G.vexs[i]);/*打印頂點,也可以其他操作*/
? ? ?for(j = 0; j < G.numVertexes; j++)
? ? ? ? ? ? ? ?if(G.arc[i][j] == 1 && !visited[j])
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DFS(G, j);/*對為訪問的鄰接頂點遞歸調(diào)用*/
}
/*鄰接矩陣的深度遍歷操作*/
void DFSTraverse(MGraph G) {
? ? int i;
? ? for(i = 0; i < G.numVertexes; i++)
? ? ? ? ? ? ? ? ? visited[i] = FALSE;/*初始所有頂點狀態(tài)都是未訪問狀態(tài)*/
? ? ? for(i = 0; i < G.numVertexes; i++)
? ? ? ? ? ? ? ? ? if(!visited[i])/*對未訪問過的頂點調(diào)用DFS,若是連通圖,只會執(zhí)行一次*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DFS(G, i);
}
/*鄰接表的深度優(yōu)先遞歸算法*/
void DFS(GraphAdjList GL, int i) {
? ? EdgeNode *p;
? ? visited[i] = TRUE;
? ? printf("%c", GL->adjList[i].data);/*打印頂點,也可以其他操作*/
? ? p = GL->adjList[i].firstedge;
? ? while(p) {
? ? ? ? ?if(!visited[p->adjvex])
? ? ? ? ? ? ? ? ? ?DFS(GL, p-adjvex);/*對為訪問的鄰接頂點遞歸調(diào)用*/
? ? ? ? ?p = p ->next;
? ? ? ? }
}
/*鄰接表的深度遍歷操作*/
void DFSTraverse(GraphAdjList GL) {
? ? ? int i;
? ? ? ? for(i = 0; i < GL->numVertexes; i++)
? ? ? ? ? ? ? ? ? ?visited[i] = FALSE;/*初始所有頂點狀態(tài)都是未訪問過狀態(tài)*/
? ? ? ? ?for(i = 0; i < GL->numVertexes; i++)
? ? ? ? ? ? ? ? ? ?if(!visited[i])/*對未訪問過的頂點調(diào)用DFS,若是連通圖,只會執(zhí)行一次*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DFS(GL, i);
}
廣度優(yōu)先遍歷
/*鄰接矩陣的廣度優(yōu)先遍歷*/
void BFSTraverse(MGraph G) {
? ? ? ?int i, j;
? ? ? ?Queue Q;
? ? ? ? for(i =0; i < G.numVertexes; i++)
? ? ? ? ? ? ? ? ?visited[i] = FALSE;
? ? ? ? ? InitQueue(&Q);/*初始化一輔助隊列*/
? ? ? ? ? for(i = 0; i < G.numVertexes; i++)/*對每一個頂點做循環(huán)*/
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? if(!visited[i]){/*若是未訪問過就處理*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? visited[i] = TRUE;/設(shè)置當(dāng)前頂點訪問過*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("%c", G.vexs[i]);/*打印頂點,也可以其他操作*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?EnQueue(&Q,i);/*將此頂點入隊列*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? while(!QueueEmpty(Q)){ /*若當(dāng)前隊列不為空*/?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeQueue(&Q, &i);/*將隊中元素出隊列,賦值給i*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?for(j = 0; j< G.numVertexes; j++) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*判斷其他頂點若與當(dāng)前頂點存在邊且未訪問過*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(G.arc[i][j] == 1 && !visited[j]) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?visited[j]=TRUE;/*找到的此頂點標(biāo)記已訪問*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("%c",G.vexs[j]);/*打印頂點*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? EnQueue(&Q, j);/*將找到的此頂點入隊列*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? }
}
/*鄰接表的廣度優(yōu)先遍歷算法*/
void BFSTraverse(GraphAdjList GL) {
? ? ? ? int i;
? ? ? ? ?EdgeNode *po;
? ? ? ? ?Queue Q;
? ? ? ? ?for(i = 0; i < GL->numVertexes; i++)
? ? ? ? ? ? ? ? ? ?visited[i] = FALSE;
? ? ? ? ? InitQueue(&Q);
? ? ? ? ? for( i = 0; i < GL->numVertexes; i++) {
? ? ? ? ? ? ? ? ? ? ? ?if(!visited[i]) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? visited[i] = TRUE;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("%c", GL->adjList[i].data);/*打印頂點,也可以其他操作*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?EnQueue(&Q, &i);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?while(!QueueEmpty(Q)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DeQueue(&Q, &i);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? p = GL ->adjList[i].firstedge; /*找到當(dāng)前頂點邊表鏈表頭指針*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? while(p) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(!visitied[p->adjvex]) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?visited[p->adjvex] = TRUE;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("%c", GL->adjList[p->adjvex].data);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?EnQueue(&Q, p ->adjvex);/*將此頂點入隊列*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?p=p->next;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? }
}
最小生成樹
/*prim算法生成最小生成樹*/
void MiniSpanTree_Prim(MGraph G) {
? ? ? ? ? ? int min, i , j, k;
? ? ? ? ? ? int? adjvex[MAXVEX];/*保存相關(guān)頂點下標(biāo)*/
? ? ? ? ? ? int lowcost[MAXVEX];/*保存相關(guān)頂點間邊的權(quán)值*/
? ? ? ? ? ? lowcost[0] = 0;/*初始化第一個權(quán)值為0,即V0加入生成樹*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*lowcost的值為0,在這里就是此下標(biāo)的頂點已經(jīng)加入生成樹*/
? ? ? ? ? ? adjvex[0] = 0;/*初始化第一個頂點下標(biāo)為0*/
? ? ? ? ? ? for(i = 1; i < G.numVertexes; i ++)/*循環(huán)除小標(biāo)為0外的全部頂點*/
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?lowcost[i] = G.arc[0][i];/*將V0頂點與之有邊的權(quán)值存入數(shù)組*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? adjvex[i] = 0;/*初始化都為V0的下標(biāo)*/
? ? ? ? ? ? ?}
? ? ? ? ? ? for(i = 0; i < G.numVertexes; i++) {
? ? ? ? ? ? ? ? ? ? ? ?min = INFINITY;/*初始化最小權(quán)值*/
? ? ? ? ? ? ? ? ? ? ? j = 1; k = 0;
? ? ? ? ? ? ? ? ? ? ? while(j < G.numVertexes) { /*循環(huán)全部頂點*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(lowcost[j] != 0 && lowcost[j] < min) {/*如果權(quán)值不為0且權(quán)值小于min*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? min = lowcost[j];? ? ? ? ? ? ? ? ? ? ? /*則讓當(dāng)前權(quán)值成為最小值*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?k = j;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?j++;
? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? printf("(%d,%d)",adjvex[k], k);/*打印當(dāng)前頂點邊中權(quán)值最小邊*/
? ? ? ? ? ? ? ? ? ? ? ? ?lowcost[k] = 0;/*將當(dāng)前頂點的權(quán)值設(shè)置為0,表示此頂點已經(jīng)完成任務(wù)*/
? ? ? ? ? ? ? ? ? ? ? ? for(j = 1; j < G.numVertexes; j ++)/*循環(huán)所有頂點*/
? ? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(lowcost[j] != && G.arc[k][j] <lowcost[j]) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*若小標(biāo)為k頂點各邊權(quán)值小于此前這些頂點未被加入生成樹權(quán)值*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lowcost[j] = G.arc[i][j];/*將較小權(quán)值存入lowcost*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?adjvex[j] = k;/*將下標(biāo)為k的頂點存入adjvex*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? }
}
/*Kruskal算法生成最小生成樹*/
void MiniSpanTree_Kruskal(MGraph G) /*生成最小生成樹*/
{
? ? ? ? ? int i, n , m;
? ? ? ? ? ?Edge edges[MAXEDGE];/*定義邊集數(shù)組*/
? ? ? ? ? int parent[MAXVEX];/*定義一數(shù)組用來判斷邊與邊是否形成回路*/
? ? ? ? ? ?/*此處省略將鄰接矩陣G轉(zhuǎn)化為邊集數(shù)組edges并按權(quán)有小到大排序的代碼*/
? ? ? ? ?for(i = 0; i < G.numVertexes; i++)
? ? ? ? ? ? ? ? ? ? ?parent[i] = 0;/*初始化數(shù)組值為0*/
? ? ? ? for(i = 0; i <G.numEdges; i++) { /*循環(huán)每一條邊*/
? ? ? ? ? ? ? ? ? ? n = Find(parent, edges[i].begin);
? ? ? ? ? ? ? ? ? ? ?m = Find(parent, edges[i].end);
? ? ? ? ? ? ? ? ? ? if(n != m)/*假如n與m不等,說明此邊沒有與現(xiàn)有生成樹形成環(huán)路*/
? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?parent[n] = m;/*將此邊的結(jié)尾頂點放入下標(biāo)為起點的parent中,表示此頂點已經(jīng)在生成樹集合中*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("(%d, %d) %d", edges[i].begin, edges[i].end, edges[i].weight);
? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}
}
int Find(int *parent, int f) /*查找連線頂點的尾部下標(biāo)*/
{
? ? ?while(parent[f]>0)
? ? ? ? ? ? ? f = parent[f];
? ? ?return f;
}
最短路徑
對于網(wǎng)圖來說,最短路徑,是指兩頂點之間經(jīng)過的邊上權(quán)值之和最少的路徑,并且我們稱路徑上的第一個頂點是源點,最后一個頂點是終點。
Dijkstra算法
#define? MAXVEX? 9
#define INFINITY 65535
typedef? int? Patharc[MAXVEX];/*用于存儲最短路徑下標(biāo)的數(shù)組*/
typdef? int ShortPathTable[MAXVEX];/*用于存儲到各點最短路徑的權(quán)值和*/
/*Dijkstra算法,求有向網(wǎng)G的V0頂點到其余頂點V最短路徑P[v]及帶權(quán)長度D[v]*/
/* P[v]的值為前驅(qū)頂點下標(biāo),D[v]表示V0到V的最短路徑長度和。*/
void? ShortestPath_Dijkstra (MGraph G,int v0, Patharc *p, ShortPathTable *D) {
??? int v, w, k ,min;
???? int? final[MAXVEX];/*final[w]=1表示求得頂點V0至Vw的最短路徑*/
???? for(v=0; v< G.numberVertexes; v++)/*初始化數(shù)據(jù)*/
???? {
?????????????? final[v]= 0;/*全部頂點初始化為未知最短路徑狀態(tài)*/
??????????????? (*D)[v]= G.arc[v0][v];/*將與V0點有連線的頂點加上權(quán)值*/
???????????????? (*P)[v]=0;/*初始化路徑數(shù)組P為0*/
????????? }
?????? (*D)[v0] = 0;/*V0至V0路徑為0*/
??????? final[v0] = 1;/*V0至V0不需要路徑*/
??????? /*開始主循環(huán),每次求得V0到某個V頂點的最短路徑*/
?????? for(v=1; v< G.numVertexes; v++) {
?????????????????? min = INFINITY;/*當(dāng)前所知離V0頂點的最近距離*/
??????????????????? for(w=0; w<G.numVertexes; w++)/*尋找離V0最近的頂點*/
?????????????????? {
??????????????????????????????? if(!final[w] && (*D)[w]<min){
????????????????????????????????????????????? k = w;
?????????????????????????????????????????????? min=(*D)[w];/*w頂點離V0頂點更近*/
???????????????????????????????????? }
????????????????????????? }
???????????????????????? final[k] = 1;/*將目前找到的最近的頂點置為1*/
??????????????????????? for(w=0; w < G.numVertexes; w++) /*修正當(dāng)前最短路徑及距離*/
??????????????????????? {
???????????????????????????????????????? /*如果經(jīng)過V頂點的路徑比現(xiàn)在這條路徑的長度短的話*/
???????????????????????????????????????? if(!final[w]&& (min + G.arc[k][w] < (*D)[w]))
???????????????????????????????????????? {/*說明找到了更短的路徑,修改D[w]和P[w]*/
??????????????????????????????????????????????????????? (*D)[w] = min+G.arc[k][w];/*修改當(dāng)前路徑長度*/
????????????????????????????????????????????????????????? (*P)[w]= k;
???????????????????????????????????????????? }
??????????????????????????????? }
?????????????? }
}
Floyd算法
typedef int Pathmatirx[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];
/*Floyd算法,求網(wǎng)圖G中各頂點v到其余頂點w最短路徑P[v][w]及帶權(quán)長度D[v][w]*/
void ShortestPath_Floyd(MGraph G, Pathmatirx *P, ShortPathTable *D) {
???? int? v, w, k;
???? for(v = 0; v < G.numVertexes; ++v)/*初始化D與P*/
????? {
????????????????? for(w = 0; w < G.numVertexes; ++w)
??????????????? {
??????????????????????????? (*D)[v][w] = G.matirx[v][w];/*D[v][w]值即為對應(yīng)點間的權(quán)值*/
????????????????????????????? (*P)[v][w] = w;/*初始化P*/
????????????????? }
??????????? }
??????????? for(k = 0; k < G.numVertexes; ++k)
???????????? {
?????????????????????? for(v = 0; v < G.numVertexes; ++v)
?????????????????????? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? for(w=0; w < G.numVertexes; ++w)
???????????????????????????????????? {
????????????????????????????????????????????????? if((*D)[v][w]>(*D)[v][k]+(*D)[k][w])
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? {/*如果經(jīng)過下標(biāo)為k頂點路徑比原兩點間路徑更短*/
???????????????????????????????????????????????????? /*將當(dāng)前兩點間權(quán)值設(shè)為更小的一個*/
???????????????????????????????????????????????????????????????? (*D)[v][w] = (*D)[v][k] + (*D)[k][w];
????????????????????????????????????????????????????????????????? (*P)[v][w]= (*P)[v][k];/*路徑設(shè)置經(jīng)過下標(biāo)為k的頂點*/????????
????????????????????????????????????????? }
???????????????????????????? }
?????????????? }
???? }
}
求最短路徑代碼
for(v=0; v< G.numVertexes; v++)
{
????????? for(w = v+ 1; w < G.numVertexes; w++)
????????? {
????????????????????? printf("v%d-v%d weight:%d",v, w, D[v][w]);
???????????????????? k =P[v][w];/*獲得第一個路徑頂點下標(biāo)*/
????????????????????? printf("path: %d",v);/*打印源點*/
?????????????????????? while(k!=w)/*如果路徑頂點下標(biāo)不是終點*/
?????????????????????? {
????????????????????????????????? printf("-> %d", k );/*打印路徑頂點*/
??????????????????????????????????? k=P[k][w];/*獲得下一個路徑頂點下標(biāo)*/
???????????????????????? }
??????????????????????? printf("-> %d\n",w);/*打印終點*/
??????????????? }
???????????????? printf("\n");
}
拓?fù)渑判?/h2>
設(shè)G=(V,E)是一個具有n個頂點的有向圖,V中的頂點序列v1,v2,·····,vn,滿足若從頂點vi到vj有一條路徑,則在頂點序列中頂點vi必在頂點vj之前。則我們稱這樣的頂點序列為一個拓?fù)湫蛄小?/p>
所謂拓?fù)渑判颍鋵嵕褪菍σ粋€有向圖構(gòu)造拓?fù)湫蛄械倪^程。
拓?fù)渑判蛩惴?/h3>
結(jié)構(gòu)代碼:
typedef struct EdgeNode/*邊表結(jié)點*/
{
??????? int adjvex;/*鄰接點域,存儲該頂點對應(yīng)的下標(biāo)*/??????? int weight;/*用于存儲權(quán)值,對于非網(wǎng)圖可以不需要*/
??????? struct EdgeNode *next;/*鏈域,指向下一個鄰接點*/
}EdgeNode;
typedef struct VertexNode/*頂點表結(jié)點*/
{
??????? int in;/*頂點入度*/???????? int? data;/*頂點域,存儲頂點信息*/
??????? EdgeNode *firstedge;/*邊表頭指針*/
}VertexNode,AdjList[MAXVEX];
typedef struct
{
????? AdjList adjList;
?????? int numVertexes, numEdges;/*圖中當(dāng)前頂點數(shù)和邊數(shù)*/
}graphAdjList, *GraphAdjList;
/*拓?fù)渑判?,若GL無回路,則輸出拓?fù)渑判蛐蛄胁⒎祷豋K,若有回路返回ERROR*/
Status TopologicalSort(GraphAdjList GL)
{
??????? EdgeNode *e;
???????? int i, k, gettop;
????????? int top= 0;/*用于棧指針下標(biāo)*/
??????? int count = 0;/*用于統(tǒng)計輸出頂點的個數(shù)*/
???????? int *stack;/*建棧存儲入度為0的頂點*/
??????? stack = (int *)malloc(GL->numVertexes * sizeof(int));
??????? for(i = 0; i < GL->numVertexes; i++)
?????????????? if(GL->adjList[i].in == 0)
?????????????????????? stack[++top] = i;/*將入度為0的頂點入棧*/
?????? while(top != 0)
?????? {
?????????????? gettop=stack[top--];/*出棧*/
??????????????? printf("%d -> ",GL->adjList[gettop].data);/*打印此頂點*/
?????????????? count++;/*統(tǒng)計輸出頂點數(shù)*/
????????????? for(e=GL->adjList[gettop].firstedge; e; e= e->next)
????????????? {/*對此頂點弧表遍歷*/
???????????????????????? k=e->adjvex;
??????????????????????? if(!(--GL->adjList[k].in))/*將k號頂點鄰接點的入度減1*/
???????????????????????????????????? stack[++top]=k;/*若為0則入棧,以便于下一次循環(huán)輸出*/
???????????????? }
?????? }
????? if(count<GL->numVertexes)/*如果count小于頂點數(shù),說明存在環(huán)*/
??????????????? return? ERROR;
??????? else
??????????????? return OK;
}
關(guān)鍵路徑
路徑上各個活動所持續(xù)的時間之和稱為路徑長度,從源點到匯點具有最大長度的路徑叫關(guān)鍵路徑,在關(guān)鍵路徑上的活動叫關(guān)鍵活動。
關(guān)鍵路徑算法
全局變量:
int *etv,*ltv;/*事件最早發(fā)生時間和最遲發(fā)生時間數(shù)組*/
int *stack2;/*用于存儲拓?fù)湫蛄械臈?/
int top2;/*用于stack2的指針*/
/*拓?fù)渑判?,用于關(guān)鍵路徑計算*/
Status TopologicalSort(GraphAdjList GL) {
????? EdgeNode *e;
?????? int i, k, gettop;
?????? int top = 0;/*用于棧指針下標(biāo)*/
?????? int count = 0;/*用于統(tǒng)計輸出頂點的個數(shù)*/
?????? int *stack;/*建棧將入度為0的頂點入棧*/
??????? stack = (int *)malloc(GL->numVertexes * sizeof(int));
?????? for(i = 0; i < GL.numVertexes; i++)
??????????????? if(0 == GL->adjList[i].in)
?????????????????????? stack[++top] = i;
?????? top2= 0;/*初始化為0*/
??????? etv=(int *)malloc(GL->numVertexes * sizeof(int));/*事件最早發(fā)生時間*/
??????? for(i = 0; i < GL->numVertexes; i++)
???????????????? etv[i]=0;/*初始化為0*/
????????? stack2=(int *)malloc(GL->numVertexes * sizeof(int));/*初始化*/
????????? while(top != 0) {
????????????????? gettop=stack[top--];
????????????????? count++;
????????????????? stack2[++top2] =gettop;/*將彈出的頂點序號壓入拓?fù)湫蛄械臈?/
?????????????????? for(e = GL->adjList[gettop].firstedge; e; e= e->next) {
????????????????????????????? k = e->adjvex;
????????????????????????????? if(!(--GL->adjList[k].in))
?????????????????????????????????????? stack[++top]=k;
??????????????????????????????? if((etv[gettop] + e->weight)>etv[k])/*求各頂點事件最早發(fā)生時間值*/
?????????????????????????????????????????? etv[k] = etv[gettop] + e->weight;
???????????????????????? }
???????????? }
????????????? if(count < GL->numVertexes)
?????????????????????? return ERROR;
?????????????? else
??????????????????????? return OK;
}
/*求關(guān)鍵路徑,GL為有向網(wǎng),輸出GL的各項關(guān)鍵活動*/
void CriticalPath(GraphAdjList GL) {
???????? EdgeNode *e;
???????? int? i, gettop, k ,j;
????????? int ete, lte;/*聲明活動最早發(fā)生時間和最遲發(fā)生時間變量*/
? ? ? ? ? TopologicalSort(GL);/*求拓?fù)湫蛄校嬎銛?shù)組etv和stack2的值*/
? ? ? ? ? ? ltv = (int *)malloc(GL->numVertexes * sizeof(int));/*事件最晚發(fā)生時間*/
? ? ? ? ? for(i = 0; i < GL->numVertexes; i++)
?????????????????? ltv[i] = etv[GL->numVertexes - 1];/*初始化ltv*/
?????????? while(top2 ! = 0)/*計算ltv*/
? ? ? ? ? {
???????????????????? gettop=stack2[top2--];/*將拓?fù)湫蛄谐鰲?,后進(jìn)先出*/
? ? ? ? ? ? ? ? ??? for(e = GL->adjList[gettop].firstedge; e; e = e->next) {
? ? ? ? ? ? ? ? ? ?? /*求各頂點事件的最遲發(fā)生時間ltv值*/
??????????????????????????????? k = e->adjvex;
??????????????????????????????? if(ltv[k]- e->weight < ltv[gettop])/*求各頂點事件最晚發(fā)生時間ltv*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ltv[gettop] = ltv[k] - e->weight;
???????????????????????? }
???????????? }
???????????? for(j=0; j < GL->numVertexes; j++)/*求ete,lte和關(guān)鍵活動*/
???????????? {
??????????????????????? for(e->GL->adjList[j].firstedge; e; e= e->next) {
???????????????????????? {
?????????????????????????????????????? k= e->adjvex;
??????????????????????????????????????? ete =etv[j];/*活動最早發(fā)生時間*/
??????????????????????????????????????? lte=ltv[k] -e->weight;/*活動最遲發(fā)生時間*/
??????????????????????????????????????? if(ete == lte)/*兩者相等即在關(guān)鍵路徑上*/
????????????????????????????????????????????????? printf("<v%d,v%d> length: %d,",GL->adjList[j].data, GL->adjList[k].data,e->weight);
???????????????????????????????? }
????????????????? }
}