最小生成树算法Prim和Kruskal

最小生成树

Prim算法

lowcost数组表示的是:还未被加入生成树链的顶点到已生成的最小树链(已加入顶点的集合)的最小值。(与最短路径有所区别)

/**	Prim算法过程简介:
 * Prim以顶点作为遍历对象,适用于邻接矩阵图(稠密图),即点少线多
 * 使用lowcost记录当前已遍历的顶点的权值,每一位对应该顶点在已遍历过程中出现的最小权值
 * lowcost初始化即任意选一顶点(一般0号顶点)作起始,将邻接矩阵图中该顶点与其它顶点的权值按序填入,该顶点本身权值为0
 * 遍历初始化后的lowcost,找到最小权值min和对应顶点序号k
 * 在lowcost中将已遍历的顶点对应位置0,用于过滤已遍历的顶点(起始点本身权值为0)
 * 在邻接矩阵图中,k位顶点(第k行)按对应位将较小的权值填入lowcost
 * 遍历lowcost找到最小权值min和对应位置k,然后将k位置0
 * 依此类推每次循环遍历一个顶点,直到遍历全部顶点
 * 
 * adjvex用于记录lowcost所记录权值的对应连线关系:顶点i与顶点adjvex[i]的权值为lowcost[i]
 * 每次替换lowcost中较小的权值时,对应adjvex位也要变更,从而在找到lowcost最小权值时知道连线信息
 * 通过每次(n-1次)循环打印一次连线信息,构建一个完整的最小生成树
 */


void MiniSpanTree_Prim(MGtaph G)
{
	int min, i, j, k;
	int adjvex[MAXVEX];		// 记录权值的对应边
	int lowcost[MAXVEX];	// 保存已遍历顶点的边的较小权值
	
	lowcost[0] = 0;			// 选择起始根开始遍历
	adjvex[0] = 0;
	
	// 对起始顶点进行相关初始化操作
	for( i = 1; i < G.numVertexes; i++)
	{
		lowcost[i] = G.arc[0][i];
		adjvex[i] = 0;
	}
	
	// 开始最小生成树构建
	for( i = 1; i < G.numVertexes; i++)
	{
		min = INFINTY;		// 初始化最小权值为无穷值,表示不连通
		j = 1;
		k = 0;
		
		// 遍历全部顶点
		while(j < G.numVertexes)
		{
			// 找出lowcost数组已存储的最小权值
			if(lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];
				k = j;		// 将发现的最小权值的下标存入k,以待使用
			}
			j++;
		}
		
		// 打印当前找到的权值最小的边
		printf("(%d,%d)", adjvex[k], k);
		lowcost[k] = 0;		// 将当前顶点的权值设置为0,方便条件过滤
		
		// 对k顶点的剩余顶点进行遍历,记录较小权值和对应位信息
		for( j = 1; j < G.numVertexes; j++)
		{
			if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j]);
			{
				lowcost[j] = G.arc[k][j];
				adjvex[j] = k;
			}
		}
	}
}
Kruskal算法
/**	Kruskal算法过程简介:
 * Kruskal算法以边作为遍历对象,适用于稀疏图(邻接表),即点多边少
 * edges数组将图的边集按权值排序,然后从最小的边开始遍历
 * parent数组记录已遍历边的顶点的集合
 * parent数组表示,i顶点可以直接或间接的与parent[i]顶点连通,即第i位的值所代表的顶点与i顶点互通
 * 对于新的i顶点,若parent[i]非0,表明i顶点已经在一个链内,可以连通parent[parent[i]]等等
 * 由于parent数组中边的关系是单向记录的,所以可以找到已通链的另一端,然后将新顶点记录进去
 * 如果一条边的两个顶点都找到了同一个链端,则表明这两个顶点都已经在这条链中存在,如果加上这条边就会有环存在,即顶点被重复添加,此时应不操作
 */

// Kruskal算法
int Find(int *parent, int f)
{
	while(parent[f] > 0)
	{
		f = parent[f];
	}
	return f;
}

void MiniSpanTree_Kruskal(MGraph G)
{
	int i, n, m;
	Edge edges[MAXEDGE];
	/*记录边的集合
	typedef struct _Edge {
		int begin;
		int end;
		int weight;
	} Edge;
	// 按权值大小排序,过程省略
	*/
	int parent[MAXVEX];		// 记录已遍历顶点的集合
	for(i = 0; i < G.numVertexes; i++)
	{
		parent[i] = 0;
		// 初始化
	}
	
	for(i = 0; i < G.numEdges; i++)
	{
		// 对每一条边,从权值最小开始遍历,逐步构建parent数组
		n = Find(parent, edges[i].begin);
		// Find函数找到parent互通链的另一端出口
		// 如果不在parent链中(包括空parent),直接返回自己,独起一链
		m = Find(parent, edges[i].end);
		
		// 如果n==m,表明当前边的两个顶点都已经在parent中的同一个互通链集合中
		// 如果n和m分别在parent中不同且不互通的链中,那么m,n肯定不会相等
		if(n != m)
		{
			parent[n] = m;		// 将nm互通记录在parent中,表示此顶点已经在生成树的局部链集合中
			printf("(%d, %d) %d", edges[i].begin, edges[i].end, edges[i].weight);
		}
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值