Kruskal算法

Kruskal算法求最小生成树

输入边的个数n和点的个数m

依次输入端点以及权值

输出最小生成树

算法简述:

  1. 按权值将边从小到大排序
  2. 初始化每个端点为一个树,所有端点共同组成一个森林
  3. 按权值从小到大依次选取边集,比较端点是否同源
  4. 不同源则将两个端点合成一棵树,并将此边集加入最小生成树集中去
  5. 重复步骤3,4,直到最小生树中边集的个数为m-1
  6. 输出最小生成树

查找根

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;
}

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值