C++使用Kruskal和Prim算法实现最小生成树
很久以前就学过最小生成树之Kruskal和Prim算法,这两个算法很容易理解,但实现起来并不那么容易。最近学习了并查集算法,得知并查集可以用于实现上述两个算法后,我自己动手实现了最小生成树算法。
宏观上讲,Kruskal算法就是一个合并的过程,而Prim算法是一个吞并的过程,另外在Prim算法中还用到了一种数据结构——优先级队列,用于动态排序。由于这两个算法很容易理解,在此不再赘述。接下来给出我的源代码。
输入
第一行包含两个整数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; } }; //创建并查集 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; //用于统计最小生成树的权值之和 vector<Edge> SpanTree; //用于保存最小生成树的边 vector<int> uset(n,0); //用数组来实现并查集 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与剩余部分的边保存在优先队列中 //循环中每次选取优先队列中权值最小的边,并更新优先队列 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; }
就实现而言,Kruskal算法比Prim算法更容易,代码更易于理解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
上一篇:C语言简单实现门禁系统
栏 目:C语言
本文标题:C++使用Kruskal和Prim算法实现最小生成树
本文地址:https://www.xiuzhanwang.com/a1/Cyuyan/496.html
您可能感兴趣的文章
- 04-02func函数+在C语言 func函数在c语言中
- 04-02c语言没有round函数 round c语言
- 01-10使用OpenGL实现3D立体显示的程序代码
- 01-10深入理解C++中常见的关键字含义
- 01-10使用C++实现全排列算法的方法详解
- 01-10深入Main函数中的参数argc,argv的使用详解
- 01-10c++中inline的用法分析
- 01-10用C++实现DBSCAN聚类算法
- 01-10全排列算法的非递归实现与递归实现的方法(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实现页面的局部加载
- 01-10SublimeText编译C开发环境设置
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10delphi制作wav文件的方法
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 01-10C#中split用法实例总结