1. 程式人生 > >第七章 圖(鄰接矩陣和鄰接表建立圖並實現DFS、BFS)

第七章 圖(鄰接矩陣和鄰接表建立圖並實現DFS、BFS)

鄰接矩陣建立圖並實現圖的深度優先遍歷和廣度優先遍歷

/*
    鄰接矩陣實現圖的廣搜和深搜
*/

#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;
}