C++使用Kruskal和Prim算法實現(xiàn)最小生成樹
很久以前就學過最小生成樹之Kruskal和Prim算法,這兩個算法很容易理解,但實現(xiàn)起來并不那么容易。最近學習了并查集算法,得知并查集可以用于實現(xiàn)上述兩個算法后,我自己動手實現(xiàn)了最小生成樹算法。
宏觀上講,Kruskal算法就是一個合并的過程,而Prim算法是一個吞并的過程,另外在Prim算法中還用到了一種數據結構——優(yōu)先級隊列,用于動態(tài)排序。由于這兩個算法很容易理解,在此不再贅述。接下來給出我的源代碼。
輸入
第一行包含兩個整數n和m,n表示圖中結點個數,m表示圖中邊的條數;接下來m行,每一行包含三個整數u,v,w,表示途中存在一條邊(u,v),并且其權重為w;為了便于調試,我的程序是從文件中輸入數據的;
輸出
輸出程序選擇的最小生成樹的權值之和以及每一條邊信息;
Kruskal算法:
#include <iostream> #include <vector> #include <algorithm> #include <fstream> using namespace std; struct Edge { int u; //邊連接的一個頂點編號 int v; //邊連接另一個頂點編號 int w; //邊的權值 friend bool operator<(const Edge& E1, const Edge& E2) { return E1.w < E2.w; } }; //創(chuàng)建并查集 void MakeSet(vector<int>& uset, int n) { uset.assign(n, 0); for (int i = 0; i < n; i++) uset[i] = i; } //查找當前元素所在集合的代表元 int FindSet(vector<int>& uset, int u) { int i = u; while (uset[i] != i) i = uset[i]; return i; } void Kruskal(const vector<Edge>& edges, int n) { vector<int> uset; vector<Edge> SpanTree; int Cost = 0, e1, e2; MakeSet(uset, n); for (int i = 0; i < edges.size(); i++) //按權值從小到大的順序取邊 { e1 = FindSet(uset, edges[i].u); e2 = FindSet(uset, edges[i].v); if (e1 != e2) //若當前邊連接的兩個結點在不同集合中,選取該邊并合并這兩個集合 { SpanTree.push_back(edges[i]); Cost += edges[i].w; uset[e1] = e2; //合并當前邊連接的兩個頂點所在集合 } } cout << "Result:\n"; cout << "Cost: " << Cost << endl; cout << "Edges:\n"; for (int j = 0; j < SpanTree.size(); j++) cout << SpanTree[j].u << " " << SpanTree[j].v << " " << SpanTree[j].w << endl; cout << endl; } int main() { ifstream in("data.txt"); int n, m; in >> n >> m; vector<Edge> edges; edges.assign(m, Edge()); for (int i = 0; i < m; i++) in >> edges[i].u >> edges[i].v >> edges[i].w; sort(edges.begin(), edges.end()); //排序之后,可以以邊權值從小到大的順序選取邊 Kruskal(edges, n); in.close(); system("pause"); return 0; }
Prim算法:
#include <iostream> #include <fstream> #include <vector> #include <list> #include <queue> using namespace std; struct Node { int v; int w; Node(int a, int b) :v(a), w(b){} }; struct Edge { int u; int v; int w; Edge(int a, int b, int c) :u(a), v(b), w(c){} friend bool operator<(const Edge& E1, const Edge& E2) { return E1.w>E2.w; } }; int n, m; vector<list<Node>> Adj; priority_queue<Edge> Q; int FindSet(vector<int>& uset, int v) { int i = v; while (i != uset[i]) i = uset[i]; return i; } void Prim() { int Cost = 0; //用于統(tǒng)計最小生成樹的權值之和 vector<Edge> SpanTree; //用于保存最小生成樹的邊 vector<int> uset(n,0); //用數組來實現(xiàn)并查集 Edge E(0, 0, 0); for (int i = 0; i < n; i++) uset[i] = i; //并查集初始化 for (auto it = Adj[0].begin(); it != Adj[0].end(); it++) Q.push(Edge(0, it->v, it->w)); //根據Prim算法,開始時選取結點0,并將結點0與剩余部分的邊保存在優(yōu)先隊列中 //循環(huán)中每次選取優(yōu)先隊列中權值最小的邊,并更新優(yōu)先隊列 while (!Q.empty()) { E = Q.top(); Q.pop(); if (0 != FindSet(uset, E.v)) { Cost += E.w; SpanTree.push_back(E); uset[E.v] = E.u; for (auto it = Adj[E.v].begin(); it != Adj[E.v].end(); it++) if (0 != FindSet(uset, it->v)) Q.push(Edge(E.v, it->v, it->w)); } } cout << "Result:\n"; cout << "Cost: " << Cost << endl; cout << "Edges:\n"; for (int j = 0; j < SpanTree.size(); j++) cout << SpanTree[j].u << " " << SpanTree[j].v << " " << SpanTree[j].w << endl; cout << endl; } int main() { ifstream in("data.txt"); int u, v, w; in >> n >> m; Adj.assign(n, list<Node>()); for (int i = 0; i < m; i++) { in >> u >> v >> w; Adj[u].push_back(Node(v,w)); Adj[v].push_back(Node(u,w)); } Prim(); in.close(); system("pause"); return 0; }
就實現(xiàn)而言,Kruskal算法比Prim算法更容易,代碼更易于理解。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持我們。
您可能感興趣的文章
- 04-02func函數+在C語言 func函數在c語言中
- 04-02c語言沒有round函數 round c語言
- 01-10使用OpenGL實現(xiàn)3D立體顯示的程序代碼
- 01-10深入理解C++中常見的關鍵字含義
- 01-10使用C++實現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數中的參數argc,argv的使用詳解
- 01-10c++中inline的用法分析
- 01-10用C++實現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實現(xiàn)與遞歸實現(xiàn)的方法(C++)
- 01-10C++大數模板(推薦)


閱讀排行
本欄相關
- 04-02c語言函數調用后清空內存 c語言調用
- 04-02func函數+在C語言 func函數在c語言中
- 04-02c語言的正則匹配函數 c語言正則表達
- 04-02c語言用函數寫分段 用c語言表示分段
- 04-02c語言中對數函數的表達式 c語言中對
- 04-02c語言編寫函數冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數 round c語言
- 04-02c語言分段函數怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數 c語言中怎
- 04-02c語言調用函數求fibo C語言調用函數求
隨機閱讀
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 04-02jquery與jsp,用jquery
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢)副欄目數量限制代碼修改
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10C#中split用法實例總結