Kruskal算法
Kruskal算法(克鲁斯卡尔算法)是一种用来查找最小生成树的算法。
算法描述
先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。
算法步骤
1、新建图G,G中拥有原图中相同的节点,但没有边;
2、将原图中所有的边按权值从小到大排序;
3、从权值最小的边开始,如果这条边连接的两个节点于图G中不在同一个连通分量中(即不构成环状),则添加这条边到图G中;
4、重复3,直至图G中所有的节点都在同一个连通分量中。
算法图解
以上图为例,先新建一个新图G,G拥有上图的节点却没有边。
再将所有边按照权值从小到大的排序。
边 | 权值 |
---|---|
B–D | 2 |
A–B | 3 |
D–F | 3 |
C–F | 4 |
E–G | 5 |
A–E | 6 |
B–H | 7 |
B–G | 8 |
G–H | 10 |
F–H | 11 |
A–C | 12 |
从权值最小的B–D边开始加入图中
重复将边加入,但不能构成环状,如果构成环状则丢弃该边。
加入D–F边
加入C–F边
加入E–G边
加入A–E边
加入B–H边,在加入B–H边之后所有顶点已经联通,所以最小生成树构造完成。
算法设计
算法主要分为
1、排序函数sort,用来将所以图的权值边进行由大到小的排序
2、将边加入图中,使用并查集进行检查是否为同一联通分量。
void sort(Road data, int n)
{
int i , j;
for(i 从 1 到 n-1){
for(j 从 1 到 n-i){
if(data[j].w > data[j+1].w)//从小到大排序
{
road t = data[j];
data[j] = data[j+1];
data[j+1] = t;
}
}
}
}
int getRoot(int v[], int x) //查询该边所对应的顶点在并查集中是否同源
{
while (v[x] != x){
x = v[x];
}
return x;
}
int Kruskal(Graph g)
{
int sum = 0;
int v[Max];//建立并查集
int i;
for(i = 1 ; i <= g->n ; i++)//初始化并查集
{
v[i] = i;
}
sort(g->data , g->e);//排序
for(i = 1 ; i <= g->e ; i++){
int a , b;
a = getRoot(v,g->data[i].a);//在并查集中查找是否为同源
b = getRoot(v,g->data[i].b);
if(a != b)
{
v[a] = b;
sum += g->data[i].w;
}
}
return sum;
}
源码
https://github.com/Lu-ziyan/-/blob/master/kruskal.cpp