【資料結構】圖的基本操作——圖的構造(鄰接矩陣,鄰接表),遍歷(DFS,BFS)
阿新 • • 發佈:2018-12-24
鄰接矩陣實現如下:
/* 主題:用鄰接矩陣實現 DFS(遞迴) 與 BFS(非遞迴) 作者:Laugh 語言:C++ ******************************************* 樣例輸出如下: 請選擇圖的型別(a - 無向圖, b - 有向圖):a 請輸入總頂點數,總邊數:8 9 請依次輸入點的資訊:a b c d e f g h 輸入一條邊依附的頂點及權值 (eg: a b 6): a b 1 a c 1 b d 1 b e 1 d h 1 e h 1 c f 1 c g 1 f g 1 列印鄰接矩陣: 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 0 0 0 請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋): 1 DFS:a b d h e c f g BFS: a b c d e f g h */ #include <iostream> #include <queue> using namespace std; #define OK 1 typedef int Status; /* ————圖的鄰接矩陣儲存表示 ————*/ #define MaxInt 32767 // 表示極大值 #define MVNum 100 // 最大頂點數 bool visited[MVNum]; // 訪問標誌陣列,其初值為 “false” typedef char VerTexType; // 假設頂點的資料型別為字元型 typedef int ArcType; // 假設邊的權值型別為整型 typedef struct { VerTexType vexs[MVNum]; // 頂點表 ArcType arcs[MVNum][MVNum]; // 鄰接矩陣 int vexnum, arcnum; // 圖的當前點數和邊數 } AMGraph; int LocateVex(AMGraph G, VerTexType u) { /* 存在則返回 u 在頂點表中的下標;否則返回 -1 */ for (int i = 0; i < G.vexnum; i++) if (u == G.vexs[i]) return i; return -1; } /* ————採用鄰接矩陣表示法建立無向網 ————*/ Status CreateUDN(AMGraph &G) { int i, j, k; char flag; ArcType w; VerTexType v1, v2; cout << "請選擇圖的型別(a - 無向圖, b - 有向圖):"; cin >> flag; cout << "請輸入總頂點數,總邊數:"; cin >> G.vexnum >> G.arcnum; // 輸入總頂點數,總邊數 cout << "請依次輸入點的資訊:"; for (i = 0; i < G.vexnum; i++) // 依次輸入點的資訊 cin >> G.vexs[i]; for (i = 0; i < G.vexnum; i++) // 初始化鄰接矩陣,邊的權值均置為極大值 MaxInt for (j = 0; j < G.vexnum; j++) G.arcs[i][j] = MaxInt; cout << "輸入一條邊依附的頂點及權值 (eg: a b 6): " << 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 if (flag == 'a') G.arcs[j][i] = G.arcs[i][j]; // 置 <v1, v2> 的對稱邊 <v2, v1> 的權值為 w } return OK; } /* 返回頂點v的第一個鄰接頂點序號 */ int FirstAdjVex(AMGraph G, int v) { for(int i = 0; i < G.vexnum; i++) if(G.arcs[v][i] == 1) return i; return -1; } /* 返回頂點v的相對於w的下一個鄰接頂點序號 */ int NextAdjVex(AMGraph G, int v, int w) { for(int i = w + 1; i < G.vexnum; i++) if(G.arcs[v][i] == 1) return i; return -1; } void DFS(AMGraph G, int v) { visited[v]=true; cout<<G.vexs[v]<<" "; for(int w=FirstAdjVex(G, v); w>=0; w=NextAdjVex(G, v, w)) if(!visited[w]) DFS(G, w); } /* 深搜 */ void DFSTraverse(AMGraph G) { for(int i = 0; i < G.vexnum; i++) visited[i] = false; for(int i = 0; i < G.vexnum; i++) if(!visited[i]) DFS(G, i); } /* 廣搜,類似於樹的層次遍歷 */ void BFSTraverse(AMGraph G) { for(int i = 0; i < G.vexnum; i++) visited[i] = false; queue<int> q; for(int i = 0; i < G.vexnum; i++) { if(!visited[i]) { visited[i] = true; q.push(i); while(!q.empty()) { int v = q.front(); q.pop(); cout << G.vexs[v] << " "; for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) { if(!visited[w]) { visited[w] = true; q.push(w); } } } } } } int main() { AMGraph G; CreateUDN(G); cout << "列印鄰接矩陣:" << endl; for (int i = 0; i < G.vexnum; i++) { for (int j = 0; j < G.vexnum; j++) { if (G.arcs[i][j] != MaxInt) cout << G.arcs[i][j] << " "; else cout << '0' << " "; } cout << endl; } int flag; cout << "請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):\n"; cin >> flag; switch(flag) { case 1: cout << "DFS:"; DFSTraverse(G); cout << endl; break; case 2: cout << "BFS:"; BFSTraverse(G); cout << endl; } return 0; }
鄰接表實現如下:
/* 主題:用鄰接表實現 DFS(遞迴) 與 BFS(非遞迴) 作者:Laugh 語言:C++ ******************************************* 樣例輸出如下: 請輸入頂點數和邊數:8 9 請輸入頂點:v1 v2 v3 v4 v5 v6 v7 v8 請輸入邊: v1 v2 v1 v3 v2 v4 v2 v5 v4 v8 v5 v8 v3 v6 v3 v7 v6 v7 列印鄰接表如下: v1->v3->v2 v2->v5->v4->v1 v3->v7->v6->v1 v4->v8->v2 v5->v8->v2 v6->v7->v3 v7->v6->v3 v8->v5->v4 請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):1 DFS:v1 v3 v7 v6 v2 v5 v8 v4 BFS: v1 v3 v2 v7 v6 v5 v4 v8 */ #include <iostream> #include <string> #include <queue> using namespace std; bool visited[10]; /* 表結點 */ typedef struct ArcNode { int adjvex; // 該弧所指向的頂點的位置 ArcNode *nextarc; // 指向下一條弧的指標 } ArcNode; /* 頭結點 */ typedef struct VNode { string data; // 頂點資訊 ArcNode* firstarc; // 第一個表結點的地址,指向第一條依附該頂點的弧的指標 } VNode, AdjList[10]; typedef struct { AdjList vertices; int vexnum, arcnum; // 圖的頂點數和弧數 } ALGraph; /* 返回頂點u在圖中的位置 */ int LocateVex(ALGraph G, string u) { for(int i = 0; i < G.vexnum; i++) if(G.vertices[i].data == u) return i; return -1; } /* 構造無向圖 */ void CreateUDG(ALGraph &G) { string v1, v2; int i, j, k; cout << "請輸入頂點數和邊數:"; cin >> G.vexnum >> G.arcnum; cout << "請輸入頂點:"; for(i = 0; i < G.vexnum; i++) { cin >> G.vertices[i].data; G.vertices[i].firstarc = NULL; } cout << "請輸入邊:"; cout << endl; for(k = 0; k < G.arcnum; k++) { cin >> v1 >> v2; i = LocateVex(G, v1); j = LocateVex(G, v2); /* 插入v1的鄰接表,為了提高效率,總在表頭插入結點 */ ArcNode *arc = new ArcNode; arc->adjvex = j; arc->nextarc = G.vertices[i].firstarc; G.vertices[i].firstarc = arc; /* 插入v2的鄰接表,為了提高效率,總在表頭插入結點 */ arc = new ArcNode; arc->adjvex = i; arc->nextarc = G.vertices[j].firstarc; G.vertices[j].firstarc = arc; } } /* 列印鄰接表 */ void Print(ALGraph G) { cout<<"列印鄰接表如下:" << endl; /* 遍歷每個頂點的鄰接表 */ for(int i = 0; i < G.vexnum; i++) { cout << G.vertices[i].data; ArcNode *p = G.vertices[i].firstarc; while(p) { cout << "->" << G.vertices[p->adjvex].data; p = p->nextarc; } cout<<endl; } } /* 返回頂點v的第一個鄰接點序號 */ int FirstAdjVex(ALGraph G, int v) { ArcNode *p=G.vertices[v].firstarc; if(p) return p->adjvex; else return -1; } /* 返回頂點v的相對於w的下一個鄰接點序號 */ int NextAdjVex(ALGraph G, int v, int w) { ArcNode* p = G.vertices[v].firstarc; while(p) { if(p->adjvex == w) break; p = p->nextarc; } if(p->adjvex != w || !p->nextarc)//如果沒找到w或者w是最後一個鄰接點 return -1; return p->nextarc->adjvex; } void DFS(ALGraph G, int v) { visited[v] = true; cout << G.vertices[v].data << " "; for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) if(!visited[w]) DFS(G, w); } void DFSTraverse(ALGraph G) { for(int i = 0; i < G.vexnum; i++) visited[i] = false; for(int i = 0; i < G.vexnum; i++) if(!visited[i]) DFS(G, i); } void BFSTraverse(ALGraph G) { queue<int> q; for(int i = 0; i < G.vexnum; i++) visited[i] = false; for(int i = 0; i < G.vexnum; i++) { if(!visited[i]) { q.push(i); visited[i] = true; while(!q.empty()) { int v = q.front(); q.pop(); cout << G.vertices[v].data << " "; for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) { if (!visited[w]) { q.push(w); visited[w] = true; } } } } } } int main() { ALGraph G; CreateUDG(G); Print(G); int flag; cout << "請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):\n"; cin >> flag; switch(flag) { case 1: cout << "DFS:"; DFSTraverse(G); cout << endl; break; case 2: cout << "BFS:"; BFSTraverse(G); cout << endl; } return 0; }