图论之最小生成树——Prim算法和Kruskal算法

首先,什么是最小生成树呢
在图那里有一个概念:一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边。我们把构造连通图的最小代价生成树称为最小生成树。

以下图为例,先创建邻接矩阵

Prim算法
我个人的理解,Prim算法就是在一个图中,从任意点开始循环访问所有的点找出最小的权值,这就是最小生成树的第一条边,接着从这条边的两端顶点依次访问邻接顶点,并比较每条边的权值找出代价最小的边,直到形成一个连通图。
下面给出代码

首先是邻接矩阵的创建

struct Graph
{
	char vex;
	int arc[max_][max_];
	int vexnum, edgenum;
};
Graph G;
void CreateG(void)	//================建立邻接矩阵
{
	int i, j, a, n;
	cin >> G.vexnum >> G.edgenum;
	for (i = 0; i < G.vexnum; i++)
		for (j = 0; j < G.edgenum; j++)
		{
			if (i == j)
				G.arc[i][j] = 0;
			else
				G.arc[i][j] = MAX;
		}
	for (a = 0; a < G.edgenum; a++)
	{
		cin >> i >> j >> n;
		G.arc[i][j] = n; G.arc[j][i] = n;
	}
}

接着是Prim算法

void MiniSpanTree_Prim()
{
	int min, i, j, k, s = 0, m = 0, a[MAX];
	int adj[MAX];
	int Low[MAX];
	Low[0] = 0; adj[0] = 0;
	for (i = 1; i < G.vexnum; i++)
	{
		Low[i] = G.arc[0][i];
		adj[i] = 0;
	}
	for (i = 1; i < G.vexnum; i++)
	{
		min = MAX;
		j = 1; k = 0;
		while (j < G.vexnum)
		{
			if (!Low[j] && Low[j]<min)
			{
				min = Low[j];
				k = j;
			}
			j++;
		}
		Low[k] = 0;
		for (j = 1; j < G.vexnum; j++)
		{
			if (!Low[j] && G.arc[k][j])
			{
				Low[j] = G.arc[k][j];
				adj[j] = k;
			}
		}
	}
}

接着我们来说说Kruskal算法
Prim算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的。而Kruskal算法是以边为目标去构建的,因为权值就是在边上的,但是要考虑是否会形成环路。所以就需要用到边集数组结构(另一种图的存储结构)

边集数组的创建
在这里插入图片描述将邻接矩阵转换为边集数组

	for (i = 0; i < G.vexnum; i++)
		for (j = 0; j < i; j++)
		{
			if (G.arc[i][j] != 0 && G.arc[i][j] != MAX)
			{
				edges[a].begin = j;
				edges[a].end = i;
				edges[a].weight = G.arc[i][j];
				a++;
			}
		}
	for(i=0;i<G.vexnum;i++)
		for (j = i+1; j < G.vexnum; j++)
		{
			if (edges[i].weight > edges[j].weight)
			{
				tmp = edges[i].weight;
				edges[i].weight = edges[j].weight;
				edges[j].weight = tmp;
			}
		}

Kruskal算法

int find(int *parent, int f)
{
	while (parent[f] > 0)
		f = parent[f];
	return f;
}
void Mini_Kruskal()
{
	int i, n, m;
	int parent[MAXVEX];
	for (i = 0; i < G.vexnum; i++)
		parent[i] = 0;
	for (i = 0; i < G.vexnum; i++)
	{
		n = find(parent, edges[i].begin);
		m = find(parent, edges[i].end);
		if (n != m)
		{
			parent[n] = m;
			cout << edges[i].begin << edges[i].end << edges[i].weight;
		}
	}
}

在Kruskal算法中,我们只关注边的权值,每次都访问最小的边,并用数组parent判断是否形成环路。接着循环下去直到所有顶点都在同一连通分量上为止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值