Prim‘s algorithm : 求一個Graph的MST的C++版本
本節介紹利用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;
}
執行結果如下:
相關文章
- C++實現Prim演算法C++演算法
- 簡單的量子演算法(二):Simon's Algorithm演算法Go
- 1s內控制向某個請求請求的次數
- 由一個C++版本猜數字遊戲引起的效率問題C++遊戲
- 筆記:A Quick Tutorial on Pollard's Rho Algorithm筆記UIGo
- Manacher's Algorithm 馬拉車演算法Go演算法
- 最小生成樹的性質與prim演算法(C++實現)演算法C++
- 第一個錯誤的版本
- Microsoft Graph for Office 365請求語法ROS
- 求一個ot的專案例項
- golang 版本的 curl 請求庫Golang
- Warshall‘s algorithm 演算法的實現及優化(修改版)Go演算法優化
- 找到最長迴文字串 - Manacher's Algorithm字串Go
- 洗牌的一個C++類! (轉)C++
- C/C++—— 一個特別奇怪的C++程式C++
- java求一個整數的最小因子Java
- 一個簡單的Ajax請求例子
- c++ STL Algorithm簡單總結備忘C++Go
- 一個很酷的 Vue3 的請求庫Vue
- 求一個全能的封裝好的jdbc bean封裝JDBCBean
- 求一個高手
- 一個隨機數的類c++隨機C++
- C++的一個記日誌的程式碼C++
- 求一個獨立模型的開發示例模型
- Python求一個數的平方根Python
- Nebula Graph|如何打造多版本文件中心
- 一個極簡版本的 VUE SSR demoVue
- 定義一個求n的階乘的函式函式
- SAP S/4HANA 的各個版本覆蓋哪些業務範圍?
- C++各版本引入的新特性C++
- 求一個整數的二進位制中1的個數
- jmeter 如何將上一個請求的結果作為下一個請求的引數——使用正則提取器JMeter
- C++ 一種交換兩個數的思路C++
- c++的一個int128類C++
- 123 C++試寫一演算法,求隨機輸入的三個整數的最大值C++演算法隨機
- 如何中斷一個正在發出的請求
- 貼一個求表空間的sql 語句SQL
- PYTHON教程中“編寫一個Python指令碼”版本一的windows版本Python指令碼Windows