数据结构---克鲁斯卡尔(Kruskal)算法

一、总体思路

总体思路:以边构建
直接找最小权值的边来构建生成树,注意考虑环路的形成

二、代码实现步骤

0.结构

主要两部分
①图:由邻接矩阵构成,包括图的顶点数、边数;
②边集表:包括起点、终点、边数的权值。
结构图

#define INFINITY 65535
#define MAXVEX 20
#define MAXEDGE 20

typedef struct
{
	int arc[MAXVEX][MAXVEX];//邻接矩阵
	int numVertexes, numEdges;//顶点数、边数
}MGraph;//图
typedef struct
{
	int begin;
	int end;
	int weight;
}Edge;//边集数组结构

1.构建边集数组

①用邻接矩阵创建图

void CreateMGraph(MGraph* G)
{
	int i, j;
	G->numEdges = 15;
	G->numVertexes = 9;
	//初始化邻接矩阵
	for (i = 0; i < G->numVertexes; i++)
	{
		for (j = 0; j < G->numVertexes; j++)
		{
			if (i == j)
				G->arc[i][j] = 0;
			else
				G->arc[i][j] = G->arc[j][i] = INFINITY;
		}
	}
	G->arc[0][1] = 10;
	G->arc[0][5] = 11;
	G->arc[1][2] = 18;
	G->arc[1][8] = 12;
	G->arc[1][6] = 16;
	G->arc[2][8] = 8;
	G->arc[2][3] = 22;
	G->arc[3][8] = 21;
	G->arc[3][6] = 24;
	G->arc[3][7] = 16;
	G->arc[3][4] = 20;
	G->arc[4][7] = 7;
	G->arc[4][5] = 26;
	G->arc[5][6] = 17;
	G->arc[6][7] = 19;
	for (i = 0; i < G->numVertexes; i++)
	{
		for (j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] = G->arc[i][j];
		}
	}
}

②构建边集数组

int i, j;
	int k = 0;
	int parent[MAXVEX];//判断是否形成环的数组
	Edge edges[MAXEDGE];//边集数组,edge的结构为begin,end,weight,均为整型 
	//构建边集数组
	//将邻接矩阵转换为边集数组
	for (i = 0; i < G.numVertexes - 1; i++)
	{
		for (j = i + 1; j < G.numVertexes ; j++)
		{
			if (G.arc[i][j] < INFINITY)
			{
				edges[k].begin = i;
				edges[k].end = j;
				edges[k].weight = G.arc[i][j];
				k++;
			}
		}
	}

2.权值排序

//交换头尾、权值
void Swap(Edge* edges, int i, int j)
{
	int t;
	t = edges[i].begin;
	edges[i].begin = edges[j].begin;
	edges[j].begin = t;

	t = edges[i].weight;
	edges[i].weight = edges[j].weight;
	edges[j].weight = t;

	t = edges[i].end;
	edges[i].end = edges[j].end;
	edges[j].end = t;
}
//权值排序
void Sort(Edge edges[], MGraph* G)
{
	int i, j;
	for (i = 0; i < G->numEdges; i++)
	{
		for (j = i+1; j < G->numEdges; j++)//选择排序
		{
			if (edges[i].weight > edges[j].weight)
			{
				Swap(edges, i, j);
			}
		}
	}
	printf("权排序之后的为:\n");
	for (i = 0; i < G->numEdges; i++)
	{
		printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
	}
}

3.生成最小生成树

//非常关键
int Find(int* parent, int f)
{
	while (parent[f] > 0)//已加入生成树集合
	{
		f = parent[f];//找到与它连通的最大顶点
	}
	//若该点没有加入生成树集合,就返回该点本身
	return f;
}
void MiniSpanTree_Kruskal(MGraph G)
{
	int i, j,n,m;
	int k = 0;
	int parent[MAXVEX];//判断是否形成环的数组
	Edge edges[MAXEDGE];//边集数组,edge的结构为begin,end,weight,均为整型 
	//构建边集数组的代码
	//排序
	Sort(edges, &G);

	/* ************* 算法关键 ****************** */
	for (i = 0; i < G.numVertexes; i++)
		parent[i] = 0;//初始化数组

	printf("打印最小生成树:\n");
	for (i = 0; i < G.numEdges; i++)/* 循环每一条边 */
	{
		n = Find(parent, edges[i].begin);//从起点开始找
		m = Find(parent, edges[i].end);//从终点开始找
		if (n != m)//没有形成环
		{
			parent[n] = m;//将此边的结尾顶点 放入 下标为起点的parent中,
			              //表示该顶点已在生成树集合中
			printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);

		}
	}

}

三、完整代码

#include <stdio.h>
#include <stdlib.h>
#define INF 65535
#define MAXVEX 20
#define MAXEDGE 20

typedef struct
{
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;
typedef struct
{
	int begin;
	int end;
	int weight;
}Edge;//边集数组结构
void CreateMGraph(MGraph* G)
{
	int i, j;
	G->numEdges = 15;
	G->numVertexes = 9;
	//初始化邻接矩阵
	for (i = 0; i < G->numVertexes; i++)
	{
		for (j = 0; j < G->numVertexes; j++)
		{
			if (i == j)
				G->arc[i][j] = 0;
			else
				G->arc[i][j] = G->arc[j][i] = INF;
		}
	}
	G->arc[0][1] = 10;
	G->arc[0][5] = 11;
	G->arc[1][2] = 18;
	G->arc[1][8] = 12;
	G->arc[1][6] = 16;
	G->arc[2][8] = 8;
	G->arc[2][3] = 22;
	G->arc[3][8] = 21;
	G->arc[3][6] = 24;
	G->arc[3][7] = 16;
	G->arc[3][4] = 20;
	G->arc[4][7] = 7;
	G->arc[4][5] = 26;
	G->arc[5][6] = 17;
	G->arc[6][7] = 19;
	for (i = 0; i < G->numVertexes; i++)
	{
		for (j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] = G->arc[i][j];
		}
	}
}
//交换头尾、权值
void Swap(Edge* edges, int i, int j)
{
	int t;
	t = edges[i].begin;
	edges[i].begin = edges[j].begin;
	edges[j].begin = t;

	t = edges[i].weight;
	edges[i].weight = edges[j].weight;
	edges[j].weight = t;

	t = edges[i].end;
	edges[i].end = edges[j].end;
	edges[j].end = t;
}
//权值排序
void Sort(Edge edges[], MGraph* G)
{
	int i, j;
	for (i = 0; i < G->numEdges; i++)
	{
		for (j = i+1; j < G->numEdges; j++)//选择排序
		{
			if (edges[i].weight > edges[j].weight)
			{
				Swap(edges, i, j);
			}
		}
	}
	printf("权排序之后的为:\n");
	for (i = 0; i < G->numEdges; i++)
	{
		printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
	}
}
//非常关键
int Find(int* parent, int f)
{
	while (parent[f] > 0)//已加入边集数组
	{
		f = parent[f];//找到与它连通的最大顶点
	}
	return f;
}
void MiniSpanTree_Kruskal(MGraph G)
{
	int i, j,n,m;
	int k = 0;
	int parent[MAXVEX];//判断是否形成环的数组
	Edge edges[MAXEDGE];//边集数组,edge的结构为begin,end,weight,均为整型 
	//构建边集数组
	//将邻接矩阵转换为边集数组
	for (i = 0; i < G.numVertexes - 1; i++)
	{
		for (j = i + 1; j < G.numVertexes ; j++)
		{
			if (G.arc[i][j] < INF)
			{
				edges[k].begin = i;
				edges[k].end = j;
				edges[k].weight = G.arc[i][j];
				k++;
			}
		}
	}
	//排序
	Sort(edges, &G);

	/* ************* 算法关键 ****************** */
	for (i = 0; i < G.numVertexes; i++)
		parent[i] = 0;//初始化数组

	printf("打印最小生成树:\n");
	for (i = 0; i < G.numEdges; i++)/* 循环每一条边 */
	{
		n = Find(parent, edges[i].begin);//从起点开始找
		m = Find(parent, edges[i].end);//从终点开始找
		if (n != m)//没有形成环
		{
			parent[n] = m;//将此边的结尾顶点 放入 下标为起点的parent中,
			              //表示该顶点已在生成树集合中
			printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);

		}
	}

}
int main()
{
	MGraph G;
	CreateMGraph(&G);
	MiniSpanTree_Kruskal(G);
	return 0;
}

四、图解

关键代码(跟着代码走一遍)在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值