Prim‘s algorithm : 求一個Graph的MST的C++版本

JUAN425發表於2014-08-10

本節介紹利用Prim's algorithm求如下一個Graph的MST:



我們用A記錄MST的所有的邊。 一開始初始化為空集合。 最終, 我們返回找到的MST的邊集合A。

Q記錄下圖中的所有Vertices 的集合。

Prim’s algorithm 的虛擬碼如下:



對於Graph中的每一個vertices, 我們定義每一個vertice 的兩個屬性。 一個是key, 一個屬性是parent.

如上述演算法:

首先將所有的vertices 的key屬性都初始化為無窮大(∞, infinity), 屬性parent 設定為NULL。   如下圖:





然後, 隨機從vertices 集合V中選擇一個vertice 作為root。 我們將這個root的key 屬性設定為0(參考虛擬碼)。 (假如我們選擇了a節點)。 然後我們建立Q集合用於包含Graph 中的所有的vertices:



接下來, 執行while loop。

我們從Q中找到具有smallest key 的vertice,  在這個例子中, vertice a 具有smallest key 。 因為a 的 key 為0, 其他的節點都是無窮大。

然後我們remove a from Q, 由於a 的parent 為NULL, 所以跳過if 條件語句。 執行下面的for 語句:
然後我們update all the vertices that is adjacent to a , 例如, 先從f開始, 如果a-f 的edge 的weight 小於f 的key(這個條件當然滿足),  我們將用a-f邊權重設定為f 的key值。 以及f 的parent設定為a.。




同樣的, 對於b 同樣的操作:



然後進入第二個whileloop:

Q中具有最小的key的vertice 為f(為2)。 所以從Q中刪掉f, 由於f 的parent為a, 不是NULL,  將邊a-f 推進集合A中。  接下來, 對於f的所有的adjacent vertices(為b, c, e),做如下更新:

 



接下來, 進入第三個while迴圈:

Q中具有最小的key的vertice 為c(為1)。 所以從Q中刪掉c, 由於c的parent為f, 不是NULL,  將邊f-c 推進集合A中。  接下來, 對於c的所有的adjacent vertices(為b, d). 注意此時f 不再Q中了。 做如下更新:




Q中且為c的adjacent vertice, 具有最小的key的vertice 為b或者d(為3)。假如我們先選b.  所以從Q中刪掉b, 由於c的parent為f, 不是NULL,  將邊f-b推進集合A中。  接下來, 對於b的所有的adjacent vertice且在Q中的節點進行更新。  此時Q中沒有b 的adjacent vertices 了。



接下來, Q中具有smallest key 的vertice 為d(為3)。 



最終, 如下。




於是我們就找到了這個Graph的MST了。


程式如下:

#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

const int INT_MAX = 99999;


struct Edge {
    char vertex1;
    char vertex2;
    int weight; // edges is modeled by 2 vertices and a weight
    Edge(char v1, char v2, int w): vertex1(v1), vertex2(v2), weight(w) {}
};

struct Graph {
    vector<char> vertices; // a vector of vertices
    vector<Edge> edges; // a vector of edges

    //find all the adjacent vertices of u
    vector<pair<char, Edge>> adjacent(char u) {
        vector<pair<char, Edge>> res;
        for (Edge e: edges) {
            if (e.vertex1 == u) {
                res.push_back(make_pair(e.vertex2, e));
            } else if (e.vertex2 == u) {
                res.push_back(make_pair(e.vertex1, e));
            }
        }
        return res;
    }
};




void Prim(Graph& g)
{
    unordered_map<char, char> A;
    unordered_map<char, char> PARENT;
    unordered_map<char, int> KEY;

    for (auto c: g.vertices) {
        PARENT[c] = '\0';
        KEY[c] = INT_MAX;
    }
    KEY['a'] = 0; // root
    vector<char> Q = g.vertices;

    while (!Q.empty()) {
        char u = *min_element(Q.begin(), Q.end(),
             [&](char x, char y) {return KEY[x] < KEY[y];});
    vector<char>::iterator itr = remove(Q.begin(), Q.end(), u);
    Q.erase(itr, Q.end());
    if (PARENT[u] != '\0') {
        A[u] = PARENT[u]; // this is one edge of MST
    }
    vector<pair<char, Edge>> adj = g.adjacent(u);
    for (pair<char, Edge> v: adj) {
        if (find(Q.begin(), Q.end(), v.first) != Q.end()) {
            if (v.second.weight < KEY[v.first]) {
                PARENT[v.first] = u;
                KEY[v.first] = v.second.weight;
            }
        }
     }
    }
    for (auto e: A) {
        cout << e.first << "--" << e.second << endl;
    }


}

int main()
{
    char t[] = {'a', 'b', 'c', 'd', 'e', 'f'};
    Graph g; // created a graph
    g.vertices = vector<char>(t, t + sizeof(t)/sizeof(t[0]));

    g.edges.push_back(Edge('a', 'b', 4));
    g.edges.push_back(Edge('a', 'f', 2));
    g.edges.push_back(Edge('f', 'b', 5));
    g.edges.push_back(Edge('c', 'b', 6));
    g.edges.push_back(Edge('c', 'f', 1));
    g.edges.push_back(Edge('f', 'e', 4));
    g.edges.push_back(Edge('d', 'e', 2));
    g.edges.push_back(Edge('d', 'c', 3));


    // call the function Kruskal to find MST of graph g

    Prim(g);

    return 0;

}

執行結果如下:






相關文章