C++實現圖的遍歷和最短路徑
摘自:https://blog.csdn.net/qq_45694646/article/details/106764026
C++實現圖的基本操作
資料結構之圖(儲存,遍歷,最短路徑)
圖是一種比線性表和樹更為複雜的資料結構,它是“多對多”的關係。圖(Graph)G是由兩個集合V和E組成,記為G=(V,E)。
一、圖的鄰接矩陣儲存
鄰接矩陣法來表示圖,需要用一個二維陣列來儲存鄰接矩陣,一個一維陣列來儲存頂點資訊。用鄰接矩陣來儲存圖有它的優點也有它的缺點:
優點:容易實現圖的操作,如:求某頂點的度、判斷頂點之間是否有邊、找頂點的鄰接點等等。
缺點:n個頂點需要n*n個單元儲存邊;空間效率為O(n2)。 對稀疏圖而言尤其浪費空間。
程式碼實現
#define MaxInt 32767 //表示極大值 即無窮大 #define MVNum 100 //最大頂點數 typedef string VerTexType; //設頂點的資料型別為string,需#include<string> typedef int ArcType; //設權值型別為整型 typedef struct { VerTexType vexs[MVNum]; //頂點表 ArcType arcs[MVNum][MVNum]; //鄰接矩陣 int vexnum, arcnum; //圖的當前點數和邊數 }AMGraph;
二、用鄰接矩陣來建立無向網
【演算法思想】:
1.輸入總頂點數和總邊數
2.依次輸入點的資訊存入頂點表中
3.初始化鄰接矩陣,使每個權值初始化為極大值
4.構造鄰接矩陣
程式碼實現
bool CreateUDN(AMGraph& G) //採用鄰接矩陣表示法,建立無向網 { int i, j, k ; VerTexType v1, v2; ArcType w; cout << "請輸入圖的頂點總數和邊的總數:"; cin >> G.vexnum >> G.arcnum; //輸入總頂點數,總邊數 cout << "請依次輸入頂點資訊:" << endl; for (i = 0; i < G.vexnum; ++i) cin >> G.vexs[i]; //依次輸入頂點資訊 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化鄰接矩陣,置為無窮大 cout << "請輸入邊的資訊,格式:頭,尾,權值" << endl; for (k = 0; k < G.arcnum; ++k) { cin >> v1 >> v2 >> w; //輸入一條邊依附的頂點及權值 i = LocateVex(G, v1);j= LocateVex(G, v2); //確定v1,v2在G中的位置,即頂點陣列的下標 G.arcs[i][j] = w; //邊<v1,v2>的權值為w G.arcs[j][i] = G.arcs[i][j]; //對稱邊 } return true; }
LocateVex()函式:查詢頂點是否在頂點表中,若在則返回頂點表中的下標;否則返回-1
int LocateVex(AMGraph G, VerTexType u) {//存在則返回u在頂點表中的下標;否則返回-1 int i; for (i = 0; i < G.vexnum; ++i) if (u == G.vexs[i]) return i; return -1; }
輸出無向網的資訊
void PrintGraph(AMGraph G) { int i, j; cout << "圖的鄰接矩陣儲存資訊:" << endl; cout << "頂點資訊:" << endl; for (i = 0; i < G.vexnum; i++) cout << i << ":" << G.vexs[i] << endl; //輸出頂點資訊 cout << "鄰接矩陣資料:" << endl; for (i = 0; i < G.vexnum; i++) { for (j = 0; j < G.vexnum; j++) { if (G.arcs[i][j] == MaxInt) cout << left<<setw(6)<<"∞"; else cout << left<<setw(6) << G.arcs[i][j]; } cout << endl; } }
三、圖的遍歷
遍歷的定義:從已給的連通圖中某一頂點出發,沿著一些邊訪遍圖中所有的頂點,且使每個頂點僅被訪問一次,就叫做圖的遍歷,它是圖的基本運算
遍歷的實質:找每個頂點的鄰接點的過程
1.深度優先遍歷
簡單歸納:
(1) 訪問起始點v;
(2) 若v的第1個鄰接點沒訪問過,深度遍歷此鄰接點;
(3) 若當前鄰接點已訪問過,再找v的第2個鄰接點重新遍歷
輔助陣列:
避免重複訪問,bool visited[MVNum];初值為false,若i被訪問,則改visited[i]=true;
程式碼實現:
void DFS_AM(AMGraph G, int v) //深度優先搜尋遍歷,從第v個頂點開始 { cout <<setw(8)<< G.vexs[v]; visited[v] = true; //訪問第v個頂點,並置visited陣列對應的值為true for (int w = 0; w < G.vexnum; w++) if ((G.arcs[v][w] != 0) && (!visited[w])) DFS_AM(G,w); //G.arcs[v][w] != 0表示w是v的鄰接點,如果w未訪問,則遞迴呼叫DFS_AM }
DFS演算法效率分析:
(1)用鄰接矩陣來表示圖,遍歷圖中每一個頂點都要從頭掃描該頂點所在行,時間複雜度為O(n2)。
(2)用鄰接表來表示圖,雖然有 2e 個表結點,但只需掃描 e 個結點即可完成遍歷,加上訪問 n個頭結點的時間,時間複雜度為O(n+e)
(3)結論:稠密圖適於在鄰接矩陣上進行深度遍歷;稀疏圖適於在鄰接表上進行深度遍歷。
2.廣度優先遍歷
簡單歸納:
(1)在訪問了起始點v之後,依次訪問 v的鄰接點
(2)然後再依次訪問這些頂點中未被訪問過的鄰接點
(3)直到所有頂點都被訪問過為止
輔助佇列:
這裡用的是鏈佇列,用順序佇列(迴圈佇列)也可以。
//佇列的DAT// typedef int Elemtype; //BFS中佇列存放的是圖元素下標 typedef int Status; typedef struct QNode { Elemtype data; struct QNode* next; }*QueuePrt; typedef struct { QueuePrt front, rear; //指標形式的對頭和隊尾指標 }*LinkQueue;
要寫出佇列的基本操作函式: 初始化 Status InitQuene(LinkQueue q) ; 判空操作 bool QueueEmpty(LinkQueue Q) ; 入隊操作 Status EnQueue(LinkQueue q, Elemtype e); 出隊操作Status DeQueue(LinkQueue q, Elemtype* e); Status InitQuene(LinkQueue q) { if (NULL == q) { return -1; } q->front = NULL; q->rear = NULL; return 0; } bool QueueEmpty(LinkQueue Q) { if (NULL == Q) { return true; } if (NULL == Q->front) { return true; } return false; } Status EnQueue(LinkQueue q, Elemtype e) { QueuePrt QP = NULL; if (NULL == q) { return -1; } QP = (QueuePrt)calloc(1, sizeof(struct QNode)); QP->data = e; QP->next = NULL; if (NULL == q->front) { q->front = QP; q->rear = QP; } else { q->rear->next = QP; q->rear = QP; } return 0; } Status DeQueue(LinkQueue q, Elemtype *e) { QueuePrt QP = NULL; QueuePrt QP_prev = NULL; QueuePrt front = NULL; if (NULL == q || NULL == e) { return -1; } if (QueueEmpty(q)) { return 0; } if (NULL == q->front->next) { q->rear = NULL; } front = q->front; q->front = q->front->next; *e = front->data; free(front); return 0; }
void BFS(AMGraph G, int v) //廣度優先遍歷 { int i, j; LinkQueue Q; Q =(LinkQueue)malloc(sizeof(LinkQueue)); InitQuene(Q);//採用的是鏈佇列 for (i = 0; i < G.vexnum; i++) visited[i] = false; for (i = 0; i < G.vexnum; i++) { if (visited[i] == false) { cout << setw(8) << G.vexs[v]; visited[v] = true; //訪問第v個頂點,並置visited陣列對應值為true EnQueue(Q, v); //v進隊 while (!QueueEmpty(Q)) //佇列非空 { DeQueue(Q, &i);//隊頭元素出隊,並置為i for (j = 0; j < G.vexnum; j++) { if ((G.arcs[i][j] = !MaxInt || G.arcs[i][j] != 0) && visited[j] == false) {//檢查i的所有鄰接點 visited[j] = true; cout << setw(8) << G.vexs[j];//訪問j EnQueue(Q, j);//j入隊 } } } } } }
BFS演算法效率分析:
(1)如果使用鄰接矩陣,則BFS對於每一個被訪問到的頂點,都要迴圈檢測矩陣中的整整一行( n 個元素),總的時間代價為O(n2)。
(2)用鄰接表來表示圖,雖然有 2e 個表結點,但只需掃描 e 個結點即可完成遍歷,加上訪問 n個頭結點的時間,時間複雜度為O(n+e)。
3.DFS與BFS演算法效率比較
(1)空間複雜度相同,都是O(n)(借用了堆疊或佇列);
(2)時間複雜度只與儲存結構(鄰接矩陣或鄰接表)有關,而與搜尋路徑無關。
四、最短路徑演算法(Dijkstra演算法)
最短路徑:在帶權有向圖中A點(源點)到達B點(終點)的多條路徑中,尋找一條各邊權值之和最小的路徑,即最短路徑。
輔助結構:
陣列S[n]:記錄相應頂點是否已被確定最短距離
陣列Dist[n]:記錄源點到相應頂點路徑長度
陣列Path[n]:記錄相應頂點的前驅頂點
【Dijkstra演算法思想】
(1) 初始化:
● 將源點v0加到S中,即S[v0]=true
● 將v0到各個終點的最短路徑長度初始化為權值,即Dist[i]=G.arcs[v0][vi]
● 如果v0和頂點vi之間有弧,則將vi的前驅置為v0,即Path[i]=v0,否則Path[i]=-1
(2) 迴圈n-1次執行以下操作:
● 選擇下一條最短路徑的終點vk,使得Dist[k]=Min{Dist[i]|vi∈V-S}
● 將vk加入到S中,即S[vk]=true
● 根據條件更新從v0出發到集合V-S上任一頂點的最短路徑的長度,若條件Dist[k]+G.arcs[k][i]<Dist[i]成立,則更新Dist[i]=Dist[k]+G.arcs[k][i],同時更改vi的前驅為vk;Path[i]=k
演算法思想:
演算法流程圖
Dijkstra演算法程式碼實現:
int Dist[MVNum];//Dist存當前找到的最短路徑長度 int Path[MVNum];//當前找到的最短路徑最後一箇中轉頂點 bool S[MVNum];//標記當前是否已求出最短路徑 void ShortestPath_DIJ(AMGraph G, int v0)//求有向網G的v0頂點到其餘頂點的最短路徑 { int n, v, i, w, min; n = G.vexnum;//頂點數 for (v = 0; v < n; v++) //n個頂點依次初始化 { S[v] = false;//S初始為空集 Dist[v] = G.arcs[v0][v];//將v0到各個終點的最短路徑長度初始化為弧上的權值 if (Dist[v] < MaxInt) Path[v] = v0;//如果v0與v之間有弧,則將v的前驅置為v0 else Path[v] = -1;//無弧,置為-1 } S[v0] = true;//將v0加入S Dist[v0] = 0;//原點到原點 的距離為0 //******初始化結束,開始主迴圈,每次求得v0到某個頂點v的最短路徑,將v加入到S集 for (i = 1; i < n; i++)//n-1個頂點 { min = MaxInt; for (w = 0; w < n; w++) if (!S[w] && Dist[w] < min)//選擇一條當前的最短路徑,終點為v { v = w; min = Dist[w]; } S[v] = true;//將v加入S for (w = 0; w < n; ++w)//更新從v0出發到集合V-S上所有的最短路徑長度 if (!S[w] && (Dist[v] + G.arcs[v][w]) < Dist[w]) { Dist[w] = Dist[v] + G.arcs[v][w];//更新D[w] Path[w] = v;//更改w的前驅為v } } }
顯示函式1:輸入起點和終點,輸出最短路徑
void DisplayPath(AMGraph G, int begin, int temp) { if (Path[temp] != -1) { DisplayPath(G, begin, Path[temp]); cout << G.vexs[Path[temp]] << "-->"; } }
顯示函式2:輸入源點,輸出源點到其他各個頂點的最短路徑
void PrintPath(AMGraph G, int v) { int i, j, w; int road[MVNum];//用於儲存最短路徑頂點的下標 for (i = 0; i < MVNum; i++)road[i] = -1; for (i = 0; i < G.vexnum; i++) { if ((S[i] == true) && (i != v)) { cout << "從" << G.vexs[v] << "到" << G.vexs[i] << "的最短路徑為:" << "\t\t"<<Dist[i] <<"\t\t"; cout << G.vexs[v] << "->"; w = Path[i];//最短路徑途徑的頂點 j = 0;//為實現逆轉標記途徑頂點數 while (w != v)//回溯途徑頂點 { road[j] = w; j++; w = Path[w]; } for (j=j-1; j >= 0; j--)//輸出最短路徑 { cout << G.vexs[road[j]] << "->"; road[j] = -1; } cout << G.vexs[i] << endl; } else cout << "從" << G.vexs[v] << "到" << G.vexs[i] << "不存在路徑" << endl; } }
五、具體實驗
main函式
int main() { AMGraph G; VerTexType start, destination; //宣告起點和終點 int num_start, num_destination; //起點和終點在頂點表中的位置 VerTexType v; int num_v; int choose = -1; cout << "**********************************" << endl; cout << "* 1.建立圖" << endl; cout << "* 2.顯示圖的資訊" << endl; cout << "* 3.圖的深度優先遍歷" << endl; cout << "* 4.圖的廣度優先遍歷" << endl; cout << "* 5.輸入起點和終點,顯示最短路徑" << endl; cout << "* 6.顯示源點到各個頂點的最短路徑" << endl; cout << "* 7.退出" << endl; cout << "**********************************" << endl; while (choose != 0) { cout << "\n----------------------- \n"; cout<<"\n請輸入操作序號:"; cin >> choose; cout << endl; switch (choose) { case 1: CreateUDN(G); break; case 2: PrintGraph(G); break; case 3: cout << "深度優先遍歷:" << endl; DFS_AM(G, 0); break; case 4: cout << "廣度優先遍歷:" << endl; BFS(G); break; case 5: cout << "請依次輸入起始點、終點名稱:"; cin >> start >> destination; //計算起點與終點編號 num_start = LocateVex(G, start); num_destination = LocateVex(G, destination); ShortestPath_DIJ(G, num_start); cout << endl << "最短路徑為:"; DisplayPath(G, num_start, num_destination); cout << G.vexs[num_destination] << endl; break; case 6: cout << "請輸入源點:"; cin >> v; num_v = LocateVex(G, v); ShortestPath_DIJ(G, num_v); PrintPath(G, num_v); break; case 7: exit_1(); break; } } return 0; }
注:本文部分演算法源自《資料結構(C語言版)》第二版 嚴蔚敏 人民郵電出版社
完整程式碼,測試通過。
// https://blog.csdn.net/qq_45694646/article/details/106764026 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include <sstream> #include <iostream> #include <iomanip> using namespace std; #define MaxInt 32767 //表示極大值 即無窮大 #define MVNum 100 //最大頂點數 typedef string VerTexType; //設頂點的資料型別為string,需#include<string> typedef int ArcType; //設權值型別為整型 typedef struct { VerTexType vexs[MVNum]; //頂點表 ArcType arcs[MVNum][MVNum]; //鄰接矩陣 int vexnum, arcnum; //圖的當前點數和邊數 }AMGraph; int LocateVex(AMGraph G, VerTexType u); bool CreateUDN(AMGraph& G) //採用鄰接矩陣表示法,建立無向網 { int i, j, k ; VerTexType v1, v2; ArcType w; cout << "請輸入圖的頂點總數和邊的總數:"; cin >> G.vexnum >> G.arcnum; //輸入總頂點數,總邊數 cout << "請依次輸入頂點資訊:" << endl; for (i = 0; i < G.vexnum; ++i) cin >> G.vexs[i]; //依次輸入頂點資訊 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化鄰接矩陣,置為無窮大 cout << "請輸入邊的資訊,格式:頭,尾,權值" << endl; for (k = 0; k < G.arcnum; ++k) { cin >> v1 >> v2 >> w; //輸入一條邊依附的頂點及權值 i = LocateVex(G, v1);j= LocateVex(G, v2); //確定v1,v2在G中的位置,即頂點陣列的下標 G.arcs[i][j] = w; //邊<v1,v2>的權值為w G.arcs[j][i] = G.arcs[i][j]; //對稱邊 } return true; } int LocateVex(AMGraph G, VerTexType u) {//存在則返回u在頂點表中的下標;否則返回-1 int i; for (i = 0; i < G.vexnum; ++i) if (u == G.vexs[i]) return i; return -1; } void PrintGraph(AMGraph G) { int i, j; cout << "圖的鄰接矩陣儲存資訊:" << endl; cout << "頂點資訊:" << endl; for (i = 0; i < G.vexnum; i++) cout << i << ":" << G.vexs[i] << endl; //輸出頂點資訊 cout << "鄰接矩陣資料:" << endl; for (i = 0; i < G.vexnum; i++) { for (j = 0; j < G.vexnum; j++) { if (G.arcs[i][j] == MaxInt) cout << left<<setw(6)<<"∞"; else cout << left<<setw(6) << G.arcs[i][j]; } cout << endl; } } bool visited[MVNum] = {false}; //頂點表 void DFS_AM(AMGraph G, int v) //深度優先搜尋遍歷,從第v個頂點開始 { cout <<setw(8)<< G.vexs[v]; visited[v] = true; //訪問第v個頂點,並置visited陣列對應的值為true for (int w = 0; w < G.vexnum; w++) if ((G.arcs[v][w] != 0) && (!visited[w])) DFS_AM(G,w); //G.arcs[v][w] != 0表示w是v的鄰接點,如果w未訪問,則遞迴呼叫DFS_AM } #if 1 //佇列的DAT// typedef int Elemtype; //BFS中佇列存放的是圖元素下標 typedef int Status; typedef struct QNode { Elemtype data; struct QNode* next; }*QueuePrt; typedef struct { QueuePrt front, rear; //指標形式的對頭和隊尾指標 }LinkQueue_T; typedef struct LinkQueue_t{ QueuePrt front, rear; //指標形式的對頭和隊尾指標 }*LinkQueue; Status InitQuene(LinkQueue q) { if (NULL == q) { return -1; } q->front = NULL; q->rear = NULL; return 0; } bool QueueEmpty(LinkQueue Q) { if (NULL == Q) { return true; } if (NULL == Q->front) { return true; } return false; } Status EnQueue(LinkQueue q, Elemtype e) { QueuePrt QP = NULL; if (NULL == q) { return -1; } QP = (QueuePrt)calloc(1, sizeof(struct QNode)); QP->data = e; QP->next = NULL; if (NULL == q->front) { q->front = QP; q->rear = QP; } else { q->rear->next = QP; q->rear = QP; } return 0; } Status DeQueue(LinkQueue q, Elemtype *e) { QueuePrt QP = NULL; QueuePrt QP_prev = NULL; QueuePrt front = NULL; if (NULL == q || NULL == e) { return -1; } if (QueueEmpty(q)) { return 0; } if (NULL == q->front->next) { q->rear = NULL; } front = q->front; q->front = q->front->next; *e = front->data; free(front); return 0; } void BFS(AMGraph G, int v) //廣度優先遍歷 { int i = 0; int j = 0; LinkQueue Q = NULL; Q = (LinkQueue)calloc(1, sizeof(struct LinkQueue_t)); InitQuene(Q); // 採用的是鏈佇列 for (i = 0; i < G.vexnum; i++) { visited[i] = false; } for (i = 0; i < G.vexnum; i++) { if (visited[i] == false) { cout << setw(8) << G.vexs[v]; visited[v] = true; //訪問第v個頂點,並置visited陣列對應值為true // cout << v << endl; EnQueue(Q, v); //v進隊 while (!QueueEmpty(Q)) //佇列非空 { DeQueue(Q, &i);//隊頭元素出隊,並置為i // cout << "222" << endl; for (j = 0; j < G.vexnum; j++) { if ((G.arcs[i][j] != MaxInt && G.arcs[i][j] != 0) && visited[j] == false) {//檢查i的所有鄰接點 visited[j] = true; cout << setw(8) << G.vexs[j];//訪問j EnQueue(Q, j);//j入隊 } //cout << "231" << endl; } } } } } #endif int Dist[MVNum];//Dist存當前找到的最短路徑長度 int Path[MVNum];//當前找到的最短路徑最後一箇中轉頂點 bool S[MVNum];//標記當前是否已求出最短路徑 void ShortestPath_DIJ(AMGraph G, int v0)//求有向網G的v0頂點到其餘頂點的最短路徑 { int n, v, i, w, min; n = G.vexnum;//頂點數 for (v = 0; v < n; v++) //n個頂點依次初始化 { S[v] = false;//S初始為空集 Dist[v] = G.arcs[v0][v];//將v0到各個終點的最短路徑長度初始化為弧上的權值 if (Dist[v] < MaxInt) Path[v] = v0;//如果v0與v之間有弧,則將v的前驅置為v0 else Path[v] = -1;//無弧,置為-1 } S[v0] = true;//將v0加入S Dist[v0] = 0;//原點到原點 的距離為0 //******初始化結束,開始主迴圈,每次求得v0到某個頂點v的最短路徑,將v加入到S集 for (i = 1; i < n; i++)//n-1個頂點 { min = MaxInt; for (w = 0; w < n; w++) if (!S[w] && Dist[w] < min)//選擇一條當前的最短路徑,終點為v { v = w; min = Dist[w]; } S[v] = true;//將v加入S for (w = 0; w < n; ++w)//更新從v0出發到集合V-S上所有的最短路徑長度 if (!S[w] && (Dist[v] + G.arcs[v][w]) < Dist[w]) { Dist[w] = Dist[v] + G.arcs[v][w];//更新D[w] Path[w] = v;//更改w的前驅為v } } } void DisplayPath(AMGraph G, int begin, int temp) { if (Path[temp] != -1) { DisplayPath(G, begin, Path[temp]); cout << G.vexs[Path[temp]] << "-->"; } } void PrintPath(AMGraph G, int v) { int i, j, w; int road[MVNum];//用於儲存最短路徑頂點的下標 for (i = 0; i < MVNum; i++)road[i] = -1; for (i = 0; i < G.vexnum; i++) { if ((S[i] == true) && (i != v)) { cout << "從" << G.vexs[v] << "到" << G.vexs[i] << "的最短路徑為:" << "\t\t"<<Dist[i] <<"\t\t"; cout << G.vexs[v] << "->"; w = Path[i];//最短路徑途徑的頂點 j = 0;//為實現逆轉標記途徑頂點數 while (w != v)//回溯途徑頂點 { road[j] = w; j++; w = Path[w]; } for (j=j-1; j >= 0; j--)//輸出最短路徑 { cout << G.vexs[road[j]] << "->"; road[j] = -1; } cout << G.vexs[i] << endl; } else cout << "從" << G.vexs[v] << "到" << G.vexs[i] << "不存在路徑" << endl; } } Status add_edge(AMGraph &G, VerTexType v1, VerTexType v2, ArcType w) { int i = 0; int j = 0; i = LocateVex(G, v1);j= LocateVex(G, v2); //確定v1,v2在G中的位置,即頂點陣列的下標 G.arcs[i][j] = w; //邊<v1,v2>的權值為w G.arcs[j][i] = G.arcs[i][j]; //對稱邊 return 0; } bool CreateUDN_test(AMGraph& G) //採用鄰接矩陣表示法,建立無向網 { int i, j ; //cout << "請輸入圖的頂點總數和邊的總數:"; G.vexnum = 10; G.arcnum = 12; //輸入總頂點數,總邊數 //cout << "請依次輸入頂點資訊:" << endl; G.vexs[0] = "昆明"; G.vexs[1] = "成都"; G.vexs[2] = "西安"; G.vexs[3] = "鄭州"; G.vexs[4] = "徐州"; G.vexs[5] = "上海"; G.vexs[6] = "南昌"; G.vexs[7] = "株洲"; G.vexs[8] = "貴陽"; G.vexs[9] = "武漢"; //依次輸入頂點資訊 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化鄰接矩陣,置為無窮大 //cout << "請輸入邊的資訊,格式:頭,尾,權值" << endl; add_edge(G, "昆明", "成都", 1100); //輸入一條邊依附的頂點及權值 add_edge(G, "成都", "西安", 842 ); //輸入一條邊依附的頂點及權值 add_edge(G, "西安", "鄭州", 511 ); //輸入一條邊依附的頂點及權值 add_edge(G, "鄭州", "徐州", 349 ); //輸入一條邊依附的頂點及權值 add_edge(G, "徐州", "上海", 651 ); //輸入一條邊依附的頂點及權值 add_edge(G, "上海", "南昌", 825 ); //輸入一條邊依附的頂點及權值 add_edge(G, "南昌", "株洲", 367 ); //輸入一條邊依附的頂點及權值 add_edge(G, "株洲", "貴陽", 902 ); //輸入一條邊依附的頂點及權值 add_edge(G, "貴陽", "昆明", 639 ); //輸入一條邊依附的頂點及權值 add_edge(G, "成都", "貴陽", 967 ); //輸入一條邊依附的頂點及權值 add_edge(G, "鄭州", "武漢", 534 ); //輸入一條邊依附的頂點及權值 add_edge(G, "武漢", "株洲", 409 ); //輸入一條邊依附的頂點及權值 return true; } bool CreateUDN_test2(AMGraph& G) //採用鄰接矩陣表示法,建立無向網 { int i, j ; //cout << "請輸入圖的頂點總數和邊的總數:"; G.vexnum = 10; G.arcnum = 12; //輸入總頂點數,總邊數 //cout << "請依次輸入頂點資訊:" << endl; G.vexs[0] = "西安"; G.vexs[1] = "鄭州"; G.vexs[2] = "徐州"; G.vexs[3] = "上海"; G.vexs[4] = "南昌"; G.vexs[5] = "株洲"; G.vexs[6] = "貴陽"; G.vexs[7] = "昆明"; G.vexs[8] = "成都"; G.vexs[9] = "武漢"; //依次輸入頂點資訊 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化鄰接矩陣,置為無窮大 //cout << "請輸入邊的資訊,格式:頭,尾,權值" << endl; add_edge(G, "西安", "鄭州", 511 ); //輸入一條邊依附的頂點及權值 add_edge(G, "鄭州", "徐州", 349 ); //輸入一條邊依附的頂點及權值 add_edge(G, "鄭州", "武漢", 534 ); //輸入一條邊依附的頂點及權值 add_edge(G, "徐州", "上海", 651 ); //輸入一條邊依附的頂點及權值 add_edge(G, "上海", "南昌", 825 ); //輸入一條邊依附的頂點及權值 add_edge(G, "南昌", "株洲", 367 ); //輸入一條邊依附的頂點及權值 add_edge(G, "武漢", "株洲", 409 ); //輸入一條邊依附的頂點及權值 add_edge(G, "株洲", "貴陽", 902 ); //輸入一條邊依附的頂點及權值 add_edge(G, "貴陽", "昆明", 639 ); //輸入一條邊依附的頂點及權值 add_edge(G, "成都", "貴陽", 967 ); //輸入一條邊依附的頂點及權值 add_edge(G, "昆明", "成都", 1100); //輸入一條邊依附的頂點及權值 add_edge(G, "成都", "西安", 842 ); //輸入一條邊依附的頂點及權值 return true; } bool CreateUDN_test3(AMGraph& G) //採用鄰接矩陣表示法,建立無向網 { int i, j ; //cout << "請輸入圖的頂點總數和邊的總數:"; G.vexnum = 7; //輸入總 頂點數 G.arcnum = 6; //輸入總 邊數 //cout << "請依次輸入頂點資訊:" << endl; G.vexs[0] = "A"; G.vexs[1] = "B"; G.vexs[2] = "C"; G.vexs[3] = "D"; G.vexs[4] = "E"; G.vexs[5] = "F"; G.vexs[6] = "C.1"; //依次輸入頂點資訊 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化鄰接矩陣,置為無窮大 //cout << "請輸入邊的資訊,格式:頭,尾,權值" << endl; add_edge(G, "A", "B", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "B", "C", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C", "D", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "D", "E", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "E", "F", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C", "C.1", 1 ); //輸入一條邊依附的頂點及權值 return true; } bool CreateUDN_test4(AMGraph& G) //採用鄰接矩陣表示法,建立無向網 { int i, j ; //cout << "請輸入圖的頂點總數和邊的總數:"; G.vexnum = 10; //輸入總 頂點數 G.arcnum = 9; //輸入總 邊數 //cout << "請依次輸入頂點資訊:" << endl; G.vexs[0] = "A"; G.vexs[1] = "B"; G.vexs[2] = "C"; G.vexs[3] = "D"; G.vexs[4] = "E"; G.vexs[5] = "F"; G.vexs[6] = "C.1"; G.vexs[7] = "C.2"; G.vexs[8] = "C.3"; G.vexs[9] = "C.1.1"; //依次輸入頂點資訊 for (i = 0; i < G.vexnum; ++i) for (j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt;//初始化鄰接矩陣,置為無窮大 //cout << "請輸入邊的資訊,格式:頭,尾,權值" << endl; add_edge(G, "A", "B", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "B", "C", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C", "D", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "D", "E", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "E", "F", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C", "C.1", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C.1", "C.2", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C.2", "C.3", 1 ); //輸入一條邊依附的頂點及權值 add_edge(G, "C.1", "C.1.1", 1 ); //輸入一條邊依附的頂點及權值 return true; } int main(int argc, char *argv[]) { AMGraph G; VerTexType start, destination; //宣告起點和終點 int num_start, num_destination; //起點和終點在頂點表中的位置 VerTexType v; int num_v; int choose = -1; cout << "**********************************" << endl; cout << "* 1.建立圖" << endl; cout << "* 2.顯示圖的資訊" << endl; cout << "* 3.圖的深度優先遍歷" << endl; cout << "* 4.圖的廣度優先遍歷" << endl; cout << "* 5.輸入起點和終點,顯示最短路徑" << endl; cout << "* 6.顯示源點到各個頂點的最短路徑" << endl; cout << "* 7.退出" << endl; cout << "**********************************" << endl; CreateUDN_test4(G); while (choose != 0) { cout << "\n----------------------- \n"; cout<<"\n請輸入操作序號:"; cin >> choose; cout << endl; switch (choose) { case 1: CreateUDN(G); break; case 2: PrintGraph(G); break; case 3: cout << "深度優先遍歷:" << endl; DFS_AM(G, 0); break; case 4: cout << "廣度優先遍歷:" << endl; BFS(G, 0); break; case 5: cout << "請依次輸入起始點、終點名稱:"; cin >> start >> destination; //計算起點與終點編號 num_start = LocateVex(G, start); num_destination = LocateVex(G, destination); ShortestPath_DIJ(G, num_start); cout << endl << "最短路徑為:"; DisplayPath(G, num_start, num_destination); cout << G.vexs[num_destination] << endl; break; case 6: cout << "請輸入源點:"; cin >> v; num_v = LocateVex(G, v); ShortestPath_DIJ(G, num_v); PrintPath(G, num_v); break; case 7: exit(0); break; } } return 0; }