Kruskal算法求最小生成树
输入边的个数n和点的个数m
依次输入端点以及权值
输出最小生成树
算法简述:
- 按权值将边从小到大排序
- 初始化每个端点为一个树,所有端点共同组成一个森林
- 按权值从小到大依次选取边集,比较端点是否同源
- 不同源则将两个端点合成一棵树,并将此边集加入最小生成树集中去
- 重复步骤3,4,直到最小生树中边集的个数为m-1
- 输出最小生成树
查找根
int find(int x) //查找树的根
{
int root = x;
while (root != b[root])
root = b[root];
while (x != root)
{
int t = b[x];
b[x] = root;
x = t;
}
return root;
}
合并树
void unite(int x, int y) //合并树
{
x = find(x);
y = find(y);
if (c[x] < c[y])
{
b[x] = y;
}
else
{
b[y] = x;
if (c[x] == c[y]) c[x]++;
}
}
Kruskal算法主体
void Kruskal(int n, int m)
{
int nEdg = 0, quan = 0;
qsort(a, n, sizeof(a[0]), cmp);//将边按照权值从小到大排序
for (int i = 0; i < n && nEdg != m - 1; i++)
{
if (find(a[i].a) != find(a[i].b))//判断当前这条边的两个端点是否属于同一棵树
{
unite(a[i].a, a[i].b);//如果不是同一棵树即合并
printf("%d %d %d\n", a[i].a, a[i].b, a[i].w);
}
}
}
源代码:
#include <stdio.h>
#include <stdlib.h>
#define MAX 10000
int b[MAX], c[MAX];
typedef struct edg //定义边集
{
int a, b, w;
}Edg;
Edg a[MAX]; //创建数组储存边集
int cmp(const void *a, const void *b)//比较权值的大小
{
return ((Edg*)a)->w - ((Edg*)b)->w;
}
void Init(int n)
{
for (int i = 0; i < n; i++)
{
c[i] = 0;
b[i] = i;
}
}
int find(int x) //查找树的根
{
int root = x;
while (root != b[root])
root = b[root];
while (x != root)
{
int t = b[x];
b[x] = root;
x = t;
}
return root;
}
void unite(int x, int y) //合并树
{
x = find(x);
y = find(y);
if (c[x] < c[y])
{
b[x] = y;
}
else
{
b[y] = x;
if (c[x] == c[y]) c[x]++;
}
}
void Kruskal(int n, int m)
{
int nEdg = 0, quan = 0;
qsort(a, n, sizeof(a[0]), cmp);//将边按照权值从小到大排序
for (int i = 0; i < n && nEdg != m - 1; i++)
{
if (find(a[i].a) != find(a[i].b))//判断当前这条边的两个端点是否属于同一棵树
{
unite(a[i].a, a[i].b);//如果不是同一棵树即合并
printf("%d %d %d\n", a[i].a, a[i].b, a[i].w);
}
}
}
int main()
{
int n, m;//n为边数,m为端点数
printf("请输入边的个数和点的个数\n");
scanf("%d %d", &n, &m);
printf("请依次输入端点以及权值\n");
while (n)
{
Init(m);
for (int i = 0; i < n; i++)
{
scanf("%d %d %d", &a[i].a, &a[i].b, &a[i].w);
}
printf("最小生成树为:\n");
Kruskal(n, m);
}
return 0;
}
运行结果