Kruskal算法求最小生成树

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAX 100
#define NO INT_MAX//NO表示没有边,相当于INF

typedef struct Graph
{
	int arcnum;
	int vexnum;
	char vextex[MAX][20];
	int martrix[MAX][MAX];
}Graph;
//邻接矩阵打印输出图
void print_graph(Graph* g)
{
	for (int i = 0; i < g->vexnum; i++)
	{
		printf("\t%s", g->vextex[i]);
	}
	printf("\n");
	for (int i = 0; i < g->vexnum; i++)
	{
		printf("%s\t", g->vextex[i]);
		for (int j = 0; j < g->vexnum; j++)
		{
			if (g->martrix[i][j] == INT_MAX)
			{
				printf("∞\t");
			}
			else
			{
				printf("%d\t", g->martrix[i][j]);
			}
		}
		printf("\n");
	}
}
//定义最小生成树的边结构
typedef struct Arc
{
	int begin;
	int end;
	int weight;//在边结构中加多了一个权值weight来用于判断构造最小生成树
}Arc;
//打印最小生成树
void print_tree(Graph* g, Arc* arc, int count)
{
	printf("最小生成树:\n");
	for (int i = 0; i < count; i++)
	{
		printf("%s--->%s\n", g->vextex[arc[i].begin], g->vextex[arc[i].end]);
	}
}
//比较函数(用于在qsort中,因为qsort是一个泛函数,开始时未知函数类型,需要在调用函数时再给出),
//所以这个比较基准函数需要使用强制类型转换
int compare_arc(const void* a, const void* b)
{
	return(((Arc*)a)->weight-((Arc*)b)->weight);//强制转化为arc类型,根据边结构的weight值进行比较,如果大于则返回正数,等于则返回0,小于则返回负数
}
//克鲁斯卡尔算法
void graph_kruskal(Graph* g)
{
	//定义边结构数组arc用于保存图中存在的边
	Arc* arc = (Arc*)malloc(sizeof(Arc) * g->vexnum * g->vexnum);
	assert(arc);
	int count=0;//count用于存边
	for (int i = 0; i < g->vexnum; i++)
	{
		for (int j = 0; j < g->vexnum; j++)
		{
			if (g->martrix[i][j] != NO)
			{
				(arc + count)->begin = i;
				(arc + count)->end = j;
				(arc + count)->weight = g->martrix[i][j];
				count++;
			}
		}
	}
	//快速排序根据边权值进行排序
	//(注意快速排序是不稳定的,所以选边的顺序不是按照原顺序的)
	qsort(arc,count,sizeof(Arc),compare_arc);
	//定义parent整型数组,大小为顶点数
	int* parent = (int*)malloc(sizeof(int) * g->vexnum);
	assert(parent);
	for (int i = 0; i < g->vexnum; i++)
	{
		parent[i] = i;//初始化时先将每个结点的前驱结点都置为自身
	}
	Arc* result = (Arc*)malloc(sizeof(Arc) * g->arcnum);//result是用于存储对边进行排序后的边结构 
	assert(result);
	count = 0;//count用于跟踪已选的边的数量
	int i = 0;//i用于遍历所有的边
	printf("Kruskal的选边过程如下:\n");
	while (count < g->vexnum - 1)//当边没选够时则继续进行
	{
		int x = (arc + i)->begin;
		int y = (arc + i)->end;
		//初始化两个变量来存x和y的根节点
		int root_x = x;
		int root_y = y;
		while (parent[root_x] != root_x)
		{
			root_x = parent[root_x];//进行压缩路径,将其根节点设为根节点的根节点
		}
		while (parent[root_y] != root_y)
		{
			root_y = parent[root_y];
		}
		if (root_x != root_y)//如果不构成一个环的话
		{
			result[count] = arc[i]; //将该边加入到最小生成树中
			count++;
			printf("选择边:%s---%s,权值为:%d\n",g->vextex[x],g->vextex[y],g->martrix[x][y]);
			parent[root_x] = root_y;//将所选边前面点的前驱节点置为后边的点(也是起到类似压缩路径的效果,谁先谁后好像关系不大)
		}
		i++;
	}
	print_tree(g, arc, count);
	free(arc);
	free(result);
	free(parent);
}

int main()
{
	Graph g = { 10,7,{"A","B","C","D","E","F","G"},
		{
			{NO,50,60,NO,NO,NO,NO},
			{50,NO,NO,65,40,NO,NO},
			{60,NO,NO,52,NO,NO,45},
			{NO,65,52,NO,50,30,42},
			{NO,40,NO,50,NO,70,NO},
			{NO,NO,NO,30,70,NO,NO},
			{NO,NO,45,42,NO,NO,NO}
		} };
	print_graph(&g);
	graph_kruskal(&g);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值