圖的遍歷及最小生成樹(prim,kruskal)的實現

關於圖的介紹網上很多,這裏就不介紹了,直接上代碼:
最小生成樹算法可以看看:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html

#include <iostream>
#include <iomanip>
#include <climits>
#include <queue>
using namespace std;

#define MAX_VERTEX_NUM 20  // 頂點數量上限 
typedef char VerType;      // 頂點結構 , 頂點的字母名稱 
typedef int ArcType;       // 邊的結構 , 權值 
typedef enum {DG, UDG} GKind;  // 圖類型,{有向圖,無向圖}

// 圖的存儲結構 
typedef struct
{
    int verNum, arcNum;  // 頂點數量, 邊數量 
    GKind kind;          // 圖類型 
    VerType vertex[MAX_VERTEX_NUM];                 //頂點
    ArcType arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];   //邊 
}Graph;


void CreateGraphByArray(Graph &G);                 // 創建圖G (通過預定義的數組)
void CreateGraph(Graph &G);                        // 創建圖G (通過輸入)
int  VertexLoc(const Graph &G, const VerType &v);  // 獲取頂點v在圖G中的位置 
void PrintGraphArcs(const Graph &G);               // 輸出圖G鄰接矩陣
void DFS(const Graph G, int vi, bool visited[]);   // 圖G的深度優先遍歷的準備 
void DFS_Traverse(const Graph &G);                 // 圖G的深度優先遍歷
void BFS_Traverse(const Graph &G);                 // 圖G的廣度優先遍歷
void MinSpanTree_Prim(const Graph &G);             // 輸出圖G最小生成樹 (Prim算法)
void MinSpanTree_Kruskal(const Graph &G);          // 輸出圖G最小生成樹 (kruskal算法)


int main()
{
    Graph G;
    //CreateGraph(G);
    CreateGraphByArray(G);

    cout << "圖的鄰接矩陣: " << endl;
    PrintGraphArcs(G);

    cout << "圖的深度優先遍歷:";
    DFS_Traverse(G);
    cout << endl;

    cout << "圖的廣度優先遍歷:";
    BFS_Traverse(G);
    cout << endl;

    cout << "最小生成樹:(prim算法)"  << endl;
    MinSpanTree_Prim(G);
    cout << endl;

    cout << "最小生成樹:(kruskal算法)"  << endl;
    MinSpanTree_Kruskal(G);
    cout << endl;
    return 0;
}


void CreateGraphByArray(Graph &G)
{
    //數據例子取自課本Page168
    G.kind = UDG;

    const int vn = 6;
    VerType V[vn + 1] = {"ABCDEF"};

    const int en = 10;
    VerType V1[en + 1] = {"ADFEBADFEB"};
    VerType V2[en + 1] = {"CCCCCDFEBA"};
    ArcType E[en] = {1,5,4,6,5,5,2,6,3,6};


    // 輸入頂點 
    G.verNum = vn;
    for(int i = 0; i < G.verNum; ++ i){
        G.vertex[i] = V[i];
    }

    // 初始化鄰接矩陣 
    for(int vi = 0; vi < G.verNum; ++ vi){
        for(int vj = 0; vj < G.verNum; ++ vj){
            G.arcs[vi][vj] = INT_MAX;
        }
    }

    // 輸入邊 
    G.arcNum = en;
    for(int i = 0; i < G.arcNum; ++ i){
        VerType &v1 = V1[i], &v2 = V2[i];
        ArcType &e = E[i];
        int vi = VertexLoc(G, v1), vj = VertexLoc(G, v2);
        if(vi == G.verNum || vj == G.verNum){
            continue;
        }
        if(UDG == G.kind){
            G.arcs[vi][vj] = G.arcs[vj][vi] = e;
        }else{
            G.arcs[vi][vj] = e;
        }
    }
}


void CreateGraph(Graph &G)
{
    // 輸入圖類型 
    int k;
    cin >> k;
    if(k == 0){
        G.kind = DG;
    }else{
        G.kind = UDG;
    }

    // 輸入頂點 
    cin >> G.verNum;
    for(int i = 0; i < G.verNum; ++ i){
        cin >> G.vertex[i];
    }

    // 初始化鄰接矩陣 
    for(int vi = 0; vi < G.verNum; ++ vi){
        for(int vj = 0; vj < G.verNum; ++ vj){
            G.arcs[vi][vj] = INT_MAX;
        }
    }

    // 輸入邊 
    VerType v1, v2; ArcType e;
    cin >> G.arcNum;
    for(int i = 0; i < G.arcNum; ++ i){
        cin >> v1 >> v2 >> e;
        int vi = VertexLoc(G, v1), vj = VertexLoc(G, v2);
        if(vi == G.verNum || vj == G.verNum){
            continue;
        }
        if(UDG == G.kind){
            G.arcs[vi][vj] = G.arcs[vj][vi] = e;
        }else{
            G.arcs[vi][vj] = e;
        }
    }
}


int VertexLoc(const Graph &G, const VerType &v)
{
    for(int i = 0; i < G.verNum; ++ i){
        if(G.vertex[i] == v){
            return i;
        }
    }
    return G.verNum;
}


void PrintGraphArcs(const Graph &G)
{
    for(int vi = 0; vi < G.verNum; ++ vi){
        for(int vj = 0; vj < G.verNum; ++ vj){
            if(G.arcs[vi][vj] == INT_MAX){
                cout << setw(5) << "INF";
            }else{
                cout << setw(5) << G.arcs[vi][vj];
            }
        }
        cout << endl;
    }
}


void DFS(const Graph G, int vi, bool visited[])
{
    cout << G.vertex[vi] << " ";
    visited[vi] = true;
    for(int vj = 0; vj < G.verNum; ++ vj){
        if(G.arcs[vi][vj] != INT_MAX && !visited[vj]){
            DFS(G, vj, visited);
        }
    }
}

void DFS_Traverse(const Graph &G)
{
    bool visited[G.verNum];
    for(int vi = 0; vi < G.verNum; ++ vi){
        visited[vi] = false;
    }

    for(int vi = 0; vi < G.verNum; ++ vi){
        if(!visited[vi]){
            DFS(G, vi, visited);
        }
    }
}


void BFS_Traverse(const Graph &G)
{
    bool visited[G.verNum];
    for(int i = 0; i < G.verNum; ++ i){
        visited[i] = false;
    }

    for(int i = 0; i < G.verNum; ++ i){
        if(!visited[i]){
            queue<int> que;
            que.push(i);
            visited[i] = true;

            while(!que.empty()){
                int vi = que.front();
                cout << G.vertex[vi] << " ";
                for(int vj = 0; vj < G.verNum; ++ vj){
                    if(G.arcs[vi][vj] != INT_MAX && !visited[vj]){
                        que.push(vj);
                        visited[vj] = true;
                    }
                }
                que.pop();
            }
        }
    }
}

void MinSpanTree_Prim(const Graph &G)
{
    //輔助結構, closeedge[i]={j, w}表示頂點vi權值最小的邊,vj爲邊頂點, w爲權值 
    struct
    {
        int adjvex;        // 最小邊頂點 
        ArcType lowcost;   // 最小邊上的權值 
    }closedge[G.verNum];

    int k = 0;
    for(int j = 0; j < G.verNum; ++ j){
        if(j != k){
            closedge[j] = {k, G.arcs[k][j]};
        }
    }
    closedge[k].lowcost = 0;  //表示頂點已經被選入Enew 

    for(int i = 1; i < G.verNum; ++ i){

        /* 從Vnew選取權值最小的邊 */
        k = -1;
        for(int j = 0; j < G.verNum; ++ j){
            if(closedge[j].lowcost != 0){
                if(k == -1){
                    k = j;
                }else if(closedge[j].lowcost < closedge[k].lowcost){
                    k = j;
                }
            }
        }

        int v0 = k, u0 = closedge[k].adjvex;
        cout << G.vertex[u0] << " - " << G.vertex[v0] << endl;  //輸出邊 

        closedge[k].lowcost = 0;  //將該頂點選入Enew 

        /* 更新與新頂點相連的頂點最小權值 */
        for(int j = 0; j < G.verNum; ++ j){
            if(G.arcs[k][j] < closedge[j].lowcost){
                closedge[j] = {k, G.arcs[k][j]};
            }
        }
    }
}


void MinSpanTree_Kruskal(const Graph &G)
{
    //輔助數組 (kruskal算法)
    struct
    {
        int head;     // 邊的起點 
        int tail;     // 邊的終點 
        ArcType lowcost;  // 邊上的權值 
    }edge[G.arcNum], temp;

    //初始化edge
    if(UDG == G.kind){
        for(int i = 0, vi = 0; vi < G.verNum; ++ vi){
            for(int vj = 0; vj < vi; ++ vj){
                if(G.arcs[vi][vj] != INT_MAX){
                    edge[i].head = vi;
                    edge[i].tail = vj;
                    edge[i ++].lowcost = G.arcs[vi][vj];
                }
            }
        }
    }else{
        for(int i = 0, vi = 0; vi < G.verNum; ++ vi){
            for(int vj = 0; vj < G.verNum; ++ vj){
                if(G.arcs[vi][vj] != INT_MAX){
                    edge[i].head = vi;
                    edge[i].tail = vj;
                    edge[i ++].lowcost = G.arcs[vi][vj];
                }
            }
        }
    }

    //並根據權值從小到大排序
    for(int i = 1; i <= G.arcNum; ++ i){
        for(int j = 0; j < G.arcNum - i; ++ j){
            if(edge[j].lowcost > edge[j + 1].lowcost){
                temp = edge[j];
                edge[j] = edge[j + 1];
                edge[j + 1] = temp;
            }
        }
    }

    int vexset[G.verNum];
    for(int i = 0; i < G.verNum; ++ i){
        vexset[i] = i;
    }

    for(int i = 0; i < G.arcNum; ++ i){
        int vi = edge[i].head, vj = edge[i].tail;
        int vs1 = vexset[vi], vs2 = vexset[vj];
        if(vs1 != vs2){
            cout << G.vertex[vi] << " - " << G.vertex[vj] << endl;
            for(int j = 0; j < G.verNum; ++ j){
                if(vexset[j] == vs2){
                    vexset[j] = vs1;
                }
            }
        }
    }
}


對於這個圖:
這裏寫圖片描述

最小生成樹的圖形爲:
這裏寫圖片描述


所運行的結果如下:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章