第七章 圖(鄰接矩陣和鄰接表建立圖並實現DFS、BFS)
阿新 • • 發佈:2019-01-30
鄰接矩陣建立圖並實現圖的深度優先遍歷和廣度優先遍歷
/*
鄰接矩陣實現圖的廣搜和深搜
*/
#include<iostream>
#include<queue>
#define inf 1000000 //假設的無窮大
#define vertex_max_num 100 //設的最大頂點數
using namespace std;
typedef struct {
int v[vertex_max_num];//頂點名稱
int adj_matrix[vertex_max_num][vertex_max_num];//鄰接矩陣
int v_num, arc_num;//頂點數,弧數
int kind;//圖的種類,0有向圖,1有向網,2無向圖,3無向網
}graph;
int vis[vertex_max_num+1];//標誌陣列
//標誌陣列初始化
void init() {
memset(vis, 0, sizeof(vis));
}
//建立有向圖
void dir_graph_create(graph &G) {
cout << "請輸入要建立的有向圖的頂點數和弧數:"; cin >> G.v_num >> G.arc_num;
//結點初始化
for (int i = 1; i <= G.v_num; i++) G.v[i] = i;//對結點編號
for (int i = 1; i <= G.v_num; i++)
for (int j = 1; j <= G.v_num; j++)
G.adj_matrix[i][j] = 0;
cout << "請依次輸入鄰接可達的成對結點:" << endl;
for (int i = 1; i <= G.arc_num; i++) {
int v1, v2;
cin >> v1 >> v2;
G.adj_matrix[v1][v2] = 1 ;
}
}
//建立有向網(帶權有向圖)
void dir_net_create(graph &G) {
cout << "請輸入要建立的有向網的頂點數和弧數:"; cin >> G.v_num >> G.arc_num;
//結點初始化
for (int i = 1; i <= G.v_num; i++) G.v[i] = i;//對結點編號
for (int i = 1; i <= G.v_num; i++)
for (int j = 1; j <= G.v_num; j++)
G.adj_matrix[i][j] = inf;
cout << "請依次輸入鄰接可達的成對結點及弧長:" << endl;
for (int i = 1; i <= G.arc_num; i++) {
int v1, v2,w;
cin >> v1 >> v2 >> w;
G.adj_matrix[v1][v2] = w;
}
}
//建立無向圖
void udir_graph_create(graph &G) {
cout << "請輸入要建立的無向圖的頂點數和弧數:"; cin >> G.v_num >> G.arc_num;
//結點初始化
for (int i = 1; i <= G.v_num; i++) G.v[i] = i;//對結點編號
for (int i = 1; i <= G.v_num; i++)
for (int j = 1; j <= G.v_num; j++)
G.adj_matrix[i][j] = 0;
cout << "請依次輸入鄰接的成對結點:" << endl;
for (int i = 1; i <= G.arc_num; i++) {
int v1, v2;
cin >> v1 >> v2;
G.adj_matrix[v1][v2] = 1;
G.adj_matrix[v2][v1] = 1;
}
}
//建立無向網(帶權無向圖)
void udir_net_create(graph &G) {
cout << "請輸入要建立的無向網的頂點數和弧數:"; cin >> G.v_num >> G.arc_num;
//結點初始化
for (int i = 1; i <= G.v_num; i++) G.v[i] = i;//對結點編號
for (int i = 1; i <= G.v_num; i++)
for (int j = 1; j <= G.v_num; j++)
G.adj_matrix[i][j] = inf;
cout << "請依次輸入鄰接的成對結點及弧長:" << endl;
for (int i = 1; i <= G.arc_num; i++) {
int v1, v2, w;
cin >> v1 >> v2 >> w;
G.adj_matrix[v1][v2] = w;
G.adj_matrix[v2][v1] = w;
}
}
void graph_create(graph &G) {
cout << "************" << endl;
cout << "0-----有向圖" << endl;
cout << "1-----有向網" << endl;
cout << "2-----無向圖" << endl;
cout << "3-----無向網" << endl;
cout << "************" << endl;
cout << "根據上方選單,輸入相應數字,來建立你想要型別的圖" << endl;
cin >> G.kind;
switch (G.kind) {
case 0:dir_graph_create(G); break;
case 1:dir_net_create(G); break;
case 2:udir_graph_create(G); break;
case 3:udir_net_create(G); break;
default:return;
}
}
//圖深度優先遍歷
void dfs1(graph G, int v) {
if (!vis[v]) {
cout << G.v[v]<<" ";
vis[v] = 1;
}
for (int i = 1; i <= G.v_num; i++)
if (!vis[i] && G.adj_matrix[v][i]==1)
dfs1(G, i);
}
//網深度優先遍歷
void dfs2(graph G, int v) {
if (!vis[v]) {
cout << G.v[v]<<" ";
vis[v] = 1;
}
for (int i = 1; i <= G.v_num; i++) {
if (!vis[i] && G.adj_matrix[v][i] != inf)
dfs2(G, i);
}
}
//深度優先遍歷
void dfs(graph G, int v) {
init();
cout << "深度優先遍歷結果:";
switch (G.kind) {
case 0:
case 2:dfs1(G, v); break;
case 1:
case 3:dfs2(G, v); break;
default:return;
}
cout << endl;
}
//廣度優先遍歷
void bfs(graph G, int v) {
init();
cout << "廣度優先遍歷結果:";
queue<int>que;
if (!vis[v]) {
cout << G.v[v] << " ";
vis[v] = 1;
que.push(v);
}
while (!que.empty()) {
int vertex = que.front();
que.pop();
for (int i = 1; i <= G.v_num; i++) {
if (!vis[i]) {
if (((G.kind == 0 || G.kind == 2) && G.adj_matrix[vertex][i] == 1) ||
((G.kind==1 || G.kind==3) && G.adj_matrix[vertex][i]!=inf)) {
cout << G.v[i] << " ";
vis[i] = 1;
que.push(i);
}
}
}
}
cout << endl;
}
int main() {
graph G;
graph_create(G);
dfs(G, 1);
bfs(G, 1);
return 0;
}
/*
下面樣例以此圖為例
1-3-4
|
6-2-5
|___|
下面輸入輸出樣例已去除文字說明
輸入樣例
2
6 6
1 2
1 3
2 5
2 6
3 4
5 6
輸出樣例
1 2 5 6 3 4
1 2 3 5 6 4
*/
鄰接表建立圖並實現圖的深度優先遍歷和廣度優先遍歷
/*
本程式用鄰接表實現圖的深搜和廣搜
以無向網為例,本例子中的無向網如下(邊權重沒有寫):
A-B-C
|
F-D-E
|___|
//下面是基於上面無向網的輸入輸出樣例(這裡權重都簡為1)
請輸入要建立的圖的結點數和邊數:6 6
========================================
結點資訊如下
第1個結點是A
第2個結點是B
第3個結點是C
第4個結點是D
第5個結點是E
第6個結點是F
========================================
邊資訊如下
請輸入第1條邊相連的兩個結點編號及邊的權重:1 2 1
請輸入第2條邊相連的兩個結點編號及邊的權重:1 4 1
請輸入第3條邊相連的兩個結點編號及邊的權重:2 3 1
請輸入第4條邊相連的兩個結點編號及邊的權重:4 5 1
請輸入第5條邊相連的兩個結點編號及邊的權重:4 6 1
請輸入第6條邊相連的兩個結點編號及邊的權重:5 6 1
鄰接表如下:
A→B→D
B→A→C
C→B
D→A→E→F
E→D→F
F→D→E
從各個結點出發深搜結果:
A B C D E F
B A D E F C
C B A D E F
D A B C E F
E D A B C F
F D A B C E
從各個結點出發廣搜結果:
A B D C E F
B A C D E F
C B A D E F
D A E F B C
E D F A B C
F D E A B C
*/
#include<iostream>
#include<queue>
using namespace std;
const int vertex_max = 100;
typedef char vertex_type;
//邊
typedef struct edge_node {
int vertex;//邊所指向的結點編號
struct edge_node *next;//下一條邊
}edge;
//結點
typedef struct vertex_node {
vertex_type e;//結點名字
edge *side;
}vertex;
typedef struct Graph {
vertex adj_list[vertex_max+1];//鄰接表
int w[vertex_max+1][vertex_max + 1];//邊權重
int v_num, e_num;//結點數、邊數
}graph;
bool vis[vertex_max + 1];
void init() {
memset(vis, 0, sizeof(vis));
}
//建立圖
void graph_create(graph &G) {
cout << "請輸入要建立的圖的結點數和邊數:";
cin >> G.v_num >> G.e_num;
cout << "========================================" << endl;
cout << "結點資訊如下"<<endl;
for (int i = 1; i <= G.v_num; i++) {
cout << "第" << i << "個結點是"; cin >> G.adj_list[i].e;
G.adj_list[i].side = nullptr;
}
cout << "========================================" << endl;
cout << "邊資訊如下" << endl;
for (int i = 1; i <= G.e_num; i++) {
cout << "請輸入第" << i << "條邊相連的兩個結點編號及邊的權重:";
int x, y,weight;
cin >> x >> y >> weight;
G.w[x][y] = G.w[y][x] = weight;
edge *p_edge = new edge;
edge *q_edge = new edge;
p_edge->next = nullptr; p_edge->vertex = y;
q_edge->next = nullptr; q_edge->vertex = x;
edge *tmp1 = G.adj_list[x].side;
edge *tmp2 = G.adj_list[y].side;
//把x結點指向y結點
while (tmp1) {
if (tmp1->next == nullptr) break;
tmp1 = tmp1->next;
}
if (tmp1 == nullptr) G.adj_list[x].side = p_edge;
else tmp1->next = p_edge;
//把y結點指向x結點
while (tmp2) {
if (tmp2->next == nullptr) break;
tmp2 = tmp2->next;
}
if (tmp2 == nullptr) G.adj_list[y].side = q_edge;
else tmp2->next = q_edge;
}
}
//列印鄰接表
void adj_list_print(graph G) {
for (int i = 1; i <= G.v_num; i++) {
cout << G.adj_list[i].e;
edge *tmp = G.adj_list[i].side;
while (tmp) {
cout <<"→"<< G.adj_list[tmp->vertex].e;
tmp = tmp->next;
}
cout << endl;
}
}
//深搜(從某結點出發搜尋)
void dfs1(graph G, int v) {
if (!vis[v]) {
cout << G.adj_list[v].e << " "; vis[v] = true;
}
edge *p = G.adj_list[v].side;
while (p) {
if (!vis[p->vertex]) dfs1(G, p->vertex);
p = p->next;
}
}
//深搜(從各個結點出發搜尋)
void dfs(graph G) {
for (int i = 1; i <= G.v_num; i++) {
init();
dfs1(G, i);
cout << endl;
}
}
//廣搜(從某個結點出發搜尋)
void bfs1(graph G,int i) {
init();
queue<int>que;
if (!vis[i]) {
cout << G.adj_list[i].e << " ";
que.push(i);
vis[i] = 1;
}
while (!que.empty()) {
int ii = que.front();
que.pop();
edge *p = G.adj_list[ii].side;
while (p) {
if (!vis[p->vertex]) {
cout << G.adj_list[p->vertex].e << " ";
que.push(p->vertex);
vis[p->vertex] = 1;
}
p = p->next;
}
}
}
//廣搜(從各個結點出發搜尋)
void bfs(graph G) {
for (int i = 1; i <= G.v_num; i++) {
bfs1(G, i);
cout << endl;
}
}
int main()
{
graph G;
graph_create(G);
cout << "鄰接表如下:" << endl; adj_list_print(G);
cout << "從各個結點出發深搜結果:" << endl; dfs(G);
cout << "從各個結點出發廣搜結果:" << endl; bfs(G);
return 0;
}