克鲁斯卡尔(Kruskal)算法

本文详细介绍了克鲁斯卡尔算法,用于在连通图中找到权值最小的生成树。通过排序边并避免形成回路,一步步构建最小生成树,同时解读了SeekRoot函数和辅助set的作用。通过实例演示,展示了算法的工作原理和源代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

克鲁斯卡尔算法是用来干什么的? 用于生成最小生成树

那么最小生成树又是什么? 最小生成树的定义:连通图G上的一棵各边权值之和最小的带权生成树

算法思想:

假设G是一个具有n个顶点的连通图,T是一个拥有图G的所有顶点,但不含任何边的图。将图G中的边按照权值从小到大依次选取,如果选取的边不会使图T形成回路,则使这条边成为图T中的一条边,如此进行下去,直到图T包含n-1条边,此时的图T就是图G的最小生成树。

举个例子,图G如下图,求它的最小生成树
在这里插入图片描述
将图G中的边按照权值从小到大依次选取,如果选取的边不会使图T形成回路,则使这条边成为图T中的一条边

在这里插入图片描述
在这里插入图片描述
当操作到第6步时,图T就是图G的最小生成树

这个算法的关键在于如何判断选取的边是否会使图T形成回路,我们又可以转化为判断这条边的两个顶点u,v是否在同一棵树上,也就是判断顶点u,v的根结点是否相同
所以我们可以设计一个SeekRoot函数,用它来求顶点所在树的根结点。如果两个顶点的根结点不同,则说明我们可以选取这条边,它不会使图T形成回路。
这时候我们还需要用到一个辅助数组set,用来存放各个顶点母亲结点

源代码

# include <stdio.h>
# define MAX 100
# define MAXLEN 100


typedef struct
{
	int u;
//边的起点	
	int v;
//边的终点	
	int w;
//顶点u和顶点v所形成的边的权值	
}Edge;


Edge E[MAX];
//定义全局变量
//为什么要创建一个数组?方便操作 


//创建一个无向网的边表 
int CreateEdge ()
{
	int n;
//n表示边长
    int i;
    printf ("请输入无向网的边数:");
    scanf ("%d", &n); 
    printf ("请分别输入顶点u,v和相应的权值w!\n输入格式为:(数字 数字 数字)\n");
    for (i = 0; i < n; i++)
    {
    	printf ("u v w =");
	    scanf ("%d %d %d", &E[i].u, &E[i].v, &E[i].w);
	}
	return n;
//返回边数	 	
}


//根据权值从小到大给数组排序 
int Sort (int n)
{
	int i, j;
	Edge t;
	
//如果前一个顶点的权值比后一个顶点的权值大,则交换这两个顶点的的值	
	for (i = 0; i < n-1; i++)
	{
		for (j = i+1; j < n; j++)
		{
			if (E[i].w > E[j].w)
			{
				t = E[i];
				E[i] = E[j];
				E[j] = t;
			} 
		}
	}
} 


//寻找顶点v所在树的根节点 
int SeekRoot (int Set[], int v)
{
	int i = v;
	while (Set[i] != 0)
	{
		i = Set[i];
	}
	return i;
//返回顶点v所在树的根节点
} 


void Kurskal (int n)
{
	int i;
	int v1, v2;
	int Set[MAXLEN];
	for (i = 0; i < n; i++)
	{
		Set[i] = 0;
	}
//给树的根节点初始化	
	
	i = 0;
	printf ("\n最小生成树为:\n");
	while (i < n)
	{
		v1 = SeekRoot (Set, E[i].u);
//v1为E[i].u的根节点		
		v2 = SeekRoot (Set, E[i].v);
//v2为E[i].v的根节点		
		if (v1 != v2)
//如果v1和v2的根节点不相等,即v1,v2不在同一棵树上时		
		{
		   	printf ("(%d,%d) %d\n",E[i].u, E[i].v, E[i].w);
		    Set[v1] = v2;
//合并两棵树,使新的树的根结点为v2		    
		}
		i++;
	}       
}


int main (void)
{
	int n;
	n = CreateEdge ();
	Sort (n);
	Kurskal (n);
	return 0;
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值