Kruskal是用于求出加权无向图的最小生成树的算法。核心思想:按照权值从小到大选边且不会形成环状,直到选完n-1条边(n为结点数)
最小生成树:对于无向加权图来讲,就是包含图中所有顶点的连通子图且边权之和为最小(无环状,边数为n-1)
举个例子:在几个村庄间修路,这条路可以达到每一个村庄且花费最少(权值之和最小)
给出一个连通图
首先我们将他们按照权值排序:
(0,5)权值:10 (2,3)权值:12 (1,6)权值:14 (1,2)权值:16
(3,6)权值:18 (3,4)权值:22 (4,6)权值:24 (4,5)权值:25
从小到大选边且不为环状
(0,5)没有成环,作为第一条边,此时
(2,3)没有成环,作为第二条边,此时
(1,6)没有成环,作为第三条边
(1,2)没有成环,作为第四条边
(3,6)发现已选边已经成环状,所以不选
(0,1)没有成环,作为第五条边
(3,4)没有成环,选择作为第六条边
已经选完n-1条边,且不成环状,选边结束
结果如下
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_SIZE=100;
struct Edge {
int u; //起始点
int v; //终止点
int w; //权值
};
Edge e[MAX_SIZE]; //存放图的边集的结构体数组
void addedge(int n, int u, int v, int w) { //用于添加边集
e[n].u = u;
e[n].v = v;
e[n].w = w;
}
int parent[10]; //并查集数组,存储每个节点的父节点,用于判断连通性
bool compare(Edge a, Edge b) { //用于sort函数按照权值排序
return a.w < b.w;
}
int find(int x) { //用于查找x的根节点
if (parent[x] == x) { return x; } //结束条件:直到索引==根节点的值
else {
find(parent[x]); //传入x的父节点到find
}
}
void uniontree(int a, int b) { //用于将a,b放入同一个并查集中
a = find(a);
b = find(b);
if (a != b) {
parent[b] = a;
}
}
void kruskal(int n) {
for (int i = 0;i < n;i++) { //初始化并查集,他们的根节点为本身
parent[i] = i;
}
int count = 1; //已选边数
int i = 0;
while (count < n) { //一共要找n-1条边
int u = e[i].u;
int v = e[i].v;
int w = e[i].w;
if (find(u) != find(v)) { //判断两个结点是否属于同一个树
uniontree(u, v); //合并两个树
count++; //找到的边数+1
printf("(%d,%d),权值:%d\n", u, v, w);
}
i++;
}
}
int main() {
addedge(0, 0, 1, 20);
addedge(1, 0, 5, 10);
addedge(2, 1, 2, 16);
addedge(3, 1, 6, 14);
addedge(4, 2, 3, 12);
addedge(5, 3, 4, 22);
addedge(6, 3, 6, 18);
addedge(7, 4, 5, 25);
addedge(8, 4, 6, 24);
sort(e, e + 9, compare); //按照权值进行升序排序;
kruskal(7); //一共7个结点
}
总结:Kruskal核心就是将所有边按照权值升序排序,从小到大选择边且不成环状,直到选完n-1条边为止。
此篇文章用于给总结巩固知识点,如果帮助到大家也是非常荣幸,如果文章有错误,感谢批评和指出