kruskal算法实现最小生成树(C语言版)

最小生成树其他做法:破圈法

克鲁斯卡尔的思路:
1. 从边出发,找到所有边,并以边的权值从小到大进行排序
这里用到了C中的qsort对结构体数组进行排序。
qsort需要我们提供一个cmp函数

int cmp(const void *a, const void *b)
{
	return (*(edge *)a).length - (*(edge *)b).length;
}

qsort(arr, ga->e, sizeof(edge), cmp);
// 参数分别为: 结构体数组, 
//			需要排序的个数, 
//			该结构体数组的大小,
//			排序规则函数

2.一次遍历,选择最小的权值边添加到树中(若该条边添加后,树中存在环路,则不应该添加这条边)。

我们可以通过一个尾节点数组,存放添加到树中的尾标识,若该尾标识重复出现则说明当前形成了环路

int end_index=0;
int ends[ga->n];
ends[end_index] = arr[0].en;
printf("%c到%c\n",ga->vexs[arr[0].beg],ga->vexs[arr[0].en]);
//第一条直接添加,并且输出(第一条必不可能形成回路)
// 这里的vexs[] 存放的是顶点元素


//遍历所有边
for(i=1;i<ga->e;i++) {
	
	int flag;
	for(j=0;j<=end_index;j++) {
		flag=0;
		// 如果之前走过这个点 (形成回路 则跳过这条边) 
		if (arr[i].en == ends[j]) {
			flag =1;
			break;
		}	
	}
	if(flag==0) {
		ends[++end_index] = arr[i].en;
		e_flag++;
		printf("%c到%c\n",ga->vexs[arr[i].beg],ga->vexs[arr[i].en]);
	}
	// 边数为 (顶点数-1) 则不再寻找
	if(e_flag == ga->n-1) {
		break;
	}
} 
  1. 若选择添加到树中的边数达到(总顶点数-1) 即不再寻找新的边。

完整代码:

#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 16   
typedef char VexType;                     /*顶点的数据类型*/
typedef int AdjType;            /*邻接矩阵的数据元素的类型*/
typedef struct
{
	VexType vexs[MAXVEX];				//顶点
	AdjType arcs[MAXVEX][MAXVEX];		//邻接矩阵
	int n;								//记录当前图的顶点数
	int e; //边数 
}GraphMatrix;

typedef struct treedata {
      char beg,en;   	/* beg,en是结点序号 */
      int length;     	/* 边长 */
}edge;



GraphMatrix* CreateGraph(void)			//创建无向带权图
{
	int i,j,k,e,m;
	GraphMatrix *ga;
	ga=(GraphMatrix *)malloc(sizeof(GraphMatrix));
	printf("请输入顶点的个数(不超过%d):",MAXVEX);
	scanf("%d",&(ga->n));
	getchar();

	printf("请顺序地输入各顶点的信息(序号即可,用一个字符表示):\n");
	for(i=0; i<ga->n; i++)
		ga->vexs[i]=getchar();     /*读入顶点信息,建立顶点表*/
	getchar();
	for(i=0; i<ga->n; i++)
		for(j=0; j<ga->n; j++){
			if(i==j) {
				ga->arcs[i][j]=0;
			} else {
				ga->arcs[i][j]=999;
			}
		}
			                /*邻接矩阵初始化*/
	printf("请输入边的个数:");
	scanf("%d",&e);
	ga->e = e;
	printf("请输入与边相关联的两个顶点的序号:\n");
	for(k=0;k<e;k++)
	{
		scanf("%d%d%d",&i,&j,&m);                         /*读入边以及权值*/
		ga->arcs[i][j]=m;
		ga->arcs[j][i]=m;
	}
	getchar();
	return ga;
}



void PrintGraph(GraphMatrix *ga)
{
	int i,j;
	printf("\n顶点表为:\n");
	for(i=0; i<ga->n; i++)
		printf("%4c",ga->vexs[i]);
	printf("\n邻接矩阵为:\n");
	for(i=0; i<ga->n; i++)
	{
		for(j=0; j<ga->n; j++)
			printf("%4d",ga->arcs[i][j]);
		printf("\n");
	}
}


int cmp(const void *a, const void *b)
{
	return (*(edge *)a).length - (*(edge *)b).length;
}

void kruskal(GraphMatrix *ga) {
	// 邻接矩阵到 edge[] 
	edge arr[MAXVEX];
	int i=0,j;
	
	int p=0;
	for(i;i<ga->e;i++) {
		for(j=0;j<i;j++) {
			if(ga->arcs[i][j] != 0 && ga->arcs[i][j] != 999) {
				arr[p].beg = j;
				arr[p].en = i;
				arr[p].length = ga->arcs[i][j];
				p++;
			}
		}
	}
	
	// arr[] 根据arr[].length 排序 从小到大!
	
	for(i=0;i<ga->e;i++) {
		printf("%c -> %c 值为 %d \n",ga->vexs[arr[i].beg],ga->vexs[arr[i].en],arr[i].length);
	}
	
	printf("根据length 排序后:\n");
	
	qsort(arr, ga->e, sizeof(edge), cmp);
	
	for(i=0;i<ga->e;i++) {
		printf("%c -> %c 值为 %d \n",ga->vexs[arr[i].beg],ga->vexs[arr[i].en],arr[i].length);
	}
	// 2. 筛选最小边 判断是否是回路。
	
	int e_flag = 0;
	// 如果边数为 (顶点数-1) 则不再寻找
	
	int end_index=0;
	int ends[ga->n];
	ends[end_index] = arr[0].en;
	printf("%c到%c\n",ga->vexs[arr[0].beg],ga->vexs[arr[0].en]);
	e_flag++;

	for(i=1;i<ga->e;i++) {
		
		int flag;
		for(j=0;j<=end_index;j++) {
			flag=0;
			// 如果之前走过这个点 (形成回路 则跳过这条边) 
			if (arr[i].en == ends[j]) {
				flag =1;
				break;
			}	
		}
		if(flag==0) {
			ends[++end_index] = arr[i].en;
			e_flag++;
			printf("%c到%c\n",ga->vexs[arr[i].beg],ga->vexs[arr[i].en]);
		}
		// 边数为 (顶点数-1) 则不再寻找
		if(e_flag == ga->n-1) {
			break;
		}
	} 
	
}


int main() {
	
	GraphMatrix *graph;
	graph = CreateGraph();
	PrintGraph(graph);
	kruskal(graph);
	return 0;
}

在这里插入图片描述

测试用例1:
请输入顶点的个数(不超过16):6
请顺序地输入各顶点的信息(序号即可,用一个字符表示):
012345
请输入边的个数:8
请输入与边相关联的两个顶点的序号:
0 1 1
0 2 5
0 3 2
1 4 7
1 2 3
2 5 6
3 5 8
4 5 4
输出
顶点表为:
0 1 2 3 4
邻接矩阵为:
0 1 5 2 999 9
1 0 3 999 7 9
5 3 0 999 999
2 999 999 0 999
999 7 999 999 0
999 999 6 8 4
0 -> 1 值为 1
0 -> 2 值为 5
1 -> 2 值为 3
0 -> 3 值为 2
1 -> 4 值为 7
2 -> 5 值为 6
3 -> 5 值为 8
4 -> 5 值为 4
根据length 排序后:
0 -> 1 值为 1
0 -> 3 值为 2
1 -> 2 值为 3
4 -> 5 值为 4
0 -> 2 值为 5
2 -> 5 值为 6
1 -> 4 值为 7
3 -> 5 值为 8
0到1
0到3
1到2
4到5
1到4

参考

  • 6
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Kruskal算法是一种用于求解最小生成树的贪心算法。下面是使用C语言实现Kruskal算法的步骤: 1. 定义结构体来表示边: ```c struct Edge { int src, dest, weight; }; ``` 2. 定义函数来比较两个边的权重: ```c int compare(const void* a, const void* b) { struct Edge* edge1 = (struct Edge*)a; struct Edge* edge2 = (struct Edge*)b; return edge1->weight - edge2->weight; } ``` 3. 定义函数来查找一个顶点的父节点: ```c int find(int parent[], int i) { if (parent[i] == -1) return i; return find(parent, parent[i]); } ``` 4. 定义函数来合并两个顶点的集合: ```c void unionSets(int parent[], int x, int y) { int rootX = find(parent, x); int rootY = find(parent, y); parent[rootX] = rootY; } ``` 5. 定义函数来应用Kruskal算法最小生成树: ```c void kruskalMST(struct Edge edges[], int V, int E) { // 按权重对边进行排序 qsort(edges, E, sizeof(edges[0]), compare); struct Edge result[V]; int parent[V]; memset(parent, -1, sizeof(parent)); int i = 0, j = 0; while (i < V - 1 && j < E) { struct Edge nextEdge = edges[j++]; int x = find(parent, nextEdge.src); int y = find(parent, nextEdge.dest); if (x != y) { result[i++] = nextEdge; unionSets(parent, x, y); } } printf("最小生成树的边:\n"); for (i = 0; i < V - 1; i++) { printf("%d - %d, 权重: %d\n", result[i].src, result[i].dest, result[i].weight); } } ``` 6. 在主函数中调用Kruskal算法函数,并传入边的信息: ```c int main() { int V = 4; // 顶点数 int E = 5; // 边数 struct Edge edges[] = { {0, 1, 10}, {0, 2, 6}, {0, 3, 5}, {1, 3, 15}, {2, 3, 4} }; kruskalMST(edges, V, E); return 0; } ``` 以上就是使用C语言实现Kruskal算法求解最小生成树的代码。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值