最小生成树的普利姆算法和克鲁斯卡尔算法

最小生成树的普利姆算法和克鲁斯卡尔算法

最小生成树的概念:指含有图中全部顶点的极小连通子树,包含所有顶点n,但只有足以构成一棵树的n-1条边

求最小生成树可以采用普利姆算法和克鲁斯卡尔算法
以下图为例
在这里插入图片描述
先构造带权图

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define MAX 0x7fffffff
typedef char VertexType;
typedef int EdgeType;
typedef struct
{
	//顶点数组
	VertexType vertex[MAXSIZE];
	//边的二维数组
	EdgeType arc[MAXSIZE][MAXSIZE];
	int Vertex_num;
	int Edge_num;
}Mat_graph;
int visit[MAXSIZE];
//构建带权图
void creat_graph(Mat_graph* G)
{
	G->Vertex_num = 9;
	G->Edge_num = 15;
	G->vertex[0] = 'A';
	G->vertex[1] = 'B';
	G->vertex[2] = 'C';
	G->vertex[3] = 'D';
	G->vertex[4] = 'E';
	G->vertex[5] = 'F';
	G->vertex[6] = 'G';
	G->vertex[7] = 'H';
	G->vertex[8] = 'I';
	for (int i = 0;i < G->Vertex_num;i++)
	{
		for (int j = 0;j < G->Vertex_num;j++)
		{
			if (i == j)
			{
				G->arc[i][j] = 0;
			}
			else
			{
				G->arc[i][j] = MAX;
			}
		}
	}
	G->arc[0][1] = 10;
	G->arc[0][5] = 11;
	G->arc[1][2] = 18;
	G->arc[1][6] = 16;
	G->arc[1][8] = 12;
	G->arc[2][3] = 22;
	G->arc[2][8] = 8;
	G->arc[3][4] = 20;
	G->arc[3][6] = 24;
	G->arc[3][7] = 16;
	G->arc[3][8] = 21;
	G->arc[4][5] = 26;
	G->arc[4][7] = 7;
	G->arc[5][6] = 17;
	G->arc[6][7] = 19;
	for (int i = 0;i < G->Vertex_num;i++)
	{
		for (int j = 0;j < G->Vertex_num;j++)
		{
			G->arc[j][i] = G->arc[i][j];
		}
	}
}

普利姆算法
普利姆算法:从一个顶点开始,每次比较待选的所有路径,并选择最小的路径,直到每个顶点都遍历一遍
代码实现

//普利姆算法
void  prim(Mat_graph* G)
{
	int i, j, k;
	int min;
	//待比较的权值
	int weight[MAXSIZE];
	//记录边,数组中的值表示出发点,数组下标表示到达点
	int index[MAXSIZE];
	for (i = 0;i < G->Vertex_num;i++)
	{
		weight[i] = G->arc[0][i];
		index[i] = 0;
	}
	for (int i = 1;i < G->Vertex_num;i++)
	{
		min = MAX;
		j = 0;
		k = 0;
		while (j < G->Vertex_num)
		{
			if (weight[j] != 0 && weight[j] < min)
			{
				min = weight[j];
				k = j;
			}
			j++;
		}
		printf("(%c,%c)\n", G->vertex[index[k]], G->vertex[k]);
		weight[k] = 0;
		//比较新的结点的权值,并把边记录下去
		for (int j = 0;j < G->Vertex_num;j++)
		{
			if (weight[j] != 0 && G->arc[k][j] < weight[j])
			{
				weight[j] = G->arc[k][j];
				index[j] = k;
			}
		}
	}
}

主函数

int main()
{
	Mat_graph G;
	creat_graph(&G);
	prim(&G);
	printf("\n");
	return 0;
}

运行结果

克鲁斯卡尔算法
克鲁斯卡尔算法是对边进行操作,先找权值最小的边,在依次选择,但要注意避免形成回路
代码如下
其中构造带权图的代码和上面一样

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define MAX 0x7fffffff
typedef char VertexType;
typedef int EdgeType;
typedef struct
{
	//顶点数组
	VertexType vertex[MAXSIZE];
	//边的二维数组
	EdgeType arc[MAXSIZE][MAXSIZE];
	int Vertex_num;
	int Edge_num;
}Mat_graph;
//边的存储
typedef struct
{
	int begine;
	int end;
	int weight;
}Edge;
//交换
void swap(Edge* a, Edge* b)
{
	Edge temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
//将边数组从小到大进行排序
void sortEdge(Edge edgh[], int edge_num)
{
	for (int i = 0;i < edge_num;i++)
	{
		for (int j = i + 1;j < edge_num;j++)
		{
			if (edgh[i].weight > edgh[j].weight)
			{
				swap(&edgh[i], &edgh[j]);
			}
		}
	}
}
//避免形成回路
int find(int* parent, int index)
{
	while (parent[index] > 0)
	{
		index = parent[index];
	}
	return index;
}
//克鲁斯卡尔算法
void Kruskal(Mat_graph* G)
{
	Edge edgh[MAXSIZE];
	int k = 0;
	for (int i = 0;i < G->Vertex_num;i++)
	{
		for (int j = i+1;j < G->Vertex_num;j++)
		{
			if (G->arc[i][j] < MAX)
			{
				edgh[k].begine = i;
				edgh[k].end = j;
				edgh[k].weight = G->arc[i][j];
				k++;
			}		
		}
	}
	sortEdge(&edgh, G->Edge_num);
	int parent[MAXSIZE];
	for (int i = 0;i < G->Vertex_num;i++)
	{
		parent[i] = 0;
	}
	int m, n;
	for (int i = 0;i < G->Edge_num;i++)
	{
		m = find(parent, edgh[i].begine);
		n = find(parent, edgh[i].end);
		if (m != n)
		{
			parent[m] = n;
			printf("(%c,%c) %d\n", G->vertex[edgh[i].begine], G->vertex[edgh[i].end], edgh[i].weight);
		}
	}
}

主函数

int main()
{
	Mat_graph G;
	creat_graph(&G);
	Kruskal(&G);
	printf("\n");
	return 0;
}

运行结果

在最小生成树中,库鲁斯卡尔算法针对边进行操作,适合边数少的情况。而普里斯算法针对顶点,适用于边数多的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值