C语言数据结构与算法---最小生成树 (普利姆算法)

一. 最小生成树

1. 生成树

生成树:所有顶点均由边连接在一起,但不存在回路的图

特点:

  • 生成树的顶点个数必须与图的顶点个数相同
  • 生成树是图的极小连通子图,去掉一条边则非连通
  • 一个有 n 个顶点的连通图的生成树有 n-1 条边
  • 含有 n 个顶点, n-1 条边的图不一定是生成树
  • 在生成树中在加一条边必然形成回路
  • 任意两点间路径唯一
    在这里插入图片描述
    在这里插入图片描述

2. 最小生成树

最小生成树:给定一个无向网络,在该网的所有生成树中,使得各边权值之和最小的那颗生成树称为该网的最小生成树,也叫最小代价生成树

构造最小生成树:

  1. 在生成树的构造过程中,图中 n 个顶点分属两个集合:
    ①已经落在生成树上的集合 U
    ②尚未落在生成树上的集合 V-U
  2. 在所有连通 U 中顶点和 V-U 中顶点的边中选取权值最小的边
    在这里插入图片描述

二. 普利姆(Prim)算法

1. 算法思想

  1. 设 N = (V,E) 是连通网, TE 是 N 上最小生成树中边的集合
    在这里插入图片描述
  2. 初始令 U = {u0} (u0∈V),TE = { }, 如:V1
    在这里插入图片描述
  3. 在所有 u∈U,v∈V-U的边(u,v)∈E中,找一条代价最小的边(u0,v0)。如 :(V1,V3)
    在这里插入图片描述
  4. 将(u0,v0)并入集合 TE,同时 v0 并入 U。
    在这里插入图片描述
  5. 从 V1,V3 出发的权值最小的边为(V3,V6)
    在这里插入图片描述
  6. 从 V1,V3,V6 出发的权值最小的边为(V6,V4)
    在这里插入图片描述
    依次类推:
    在这里插入图片描述
    在这里插入图片描述

2. 普利姆算法的实现

void MiniSpanTree_Prim(MGraph G)
{
	/**
	* 初始化
	*/
	int min, i, j, k;
	int adjvex[MAXVEX];  //保存相关顶点的下标
	int lowcost[MAXVEX];  //保存相关顶点间边的权值

	//lowcost值为0,即此下标的顶点已加入生成树
	lowcost[0] = 0;  //V0加入生成树
	adjvex[0] = 0;   //初始化第一个顶点下标为0

	//循环除下标为0外的全部顶点
	for (i = 1; i < G.numv; i++)
	{
		lowcost[i] = G.arc[0][i];  //将和V0有关的边的权值(邻接矩阵第0行)存入数组
		adjvex[i] = 0;     //初始化都为V0的下标
	}

	/**
	* 构造最小生成树
	*/
	for (i = 1; i < G.numv; i++)
	{
		min = INFINITY;  //初始化最小权值
		j = 1;
		k = 0;
		while (j < G.numv)  //循环所有结点
		{
			//若该结点还未加入生成树且权值小于当前最小权值
			if (lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];  //让当前权值成为最小值
				k = j;     //用k存储当前下标
			}
			j++;
		}
		while结束后找到了当前顶点到其邻接点的最小权值(邻接矩阵第0行的最小值)

		printf("(%d,%d)",adjvex[k],k);  //打印当前顶点到其权值最小的邻接点
		lowcost[k] = 0;  //当前顶点k已加入生成树,设置为0
		//循环所有顶点
		for (j = 1; j < G.numv; j++)
		{
			//若该结点还未加入生成树且该结点k的邻接点的权值小于此前这些点未被加入生成树的权值
			//-----即是将现在k的未加入生成树的邻接点的权值与在k之前就加入了生成树的结点的现在未加入生成树的邻接点的权值比较
			//-----相当于比较邻接矩阵第k行的值
			if (lowcost[j] != 0 && G.arc[k][j] < lowcost[j])
			{
				lowcost[j] = G.arc[k][j];   //将较小权值存入lowcost
				adjvex[j] = k;   //将下标为k的顶点存入adjvex
			}
		}
	}
}
  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
普利算法(Prim算法)是一种贪心算法,用于求解加权无向图的最小生成树。它的基本思想是从一个顶点开始,每次选择一条权值最小的边与已选的顶点集合相连,直到所有顶点都被选中为止。 下面是利用C语言实现普利算法生成无向带权图的最小生成树的代码: ```c #include<stdio.h> #include<limits.h> #define V 5 //顶点数 #define INF INT_MAX //无穷大 //找到未被包含在最小生成树中的最小权值的顶点 int minKey(int key[], int mstSet[]) { int min = INF, min_index; for(int i = 0; i < V; i++) if(mstSet[i] == 0 && key[i] < min) min = key[i], min_index = i; return min_index; } //打印生成的最小生成树 void printMST(int parent[], int graph[V][V]) { printf("Edge \tWeight\n"); for(int i = 1; i < V; i++) printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]); } //生成无向带权图的最小生成树 void primMST(int graph[V][V]) { int parent[V]; //存储生成树的父节点 int key[V]; //用于选择最小权值的顶点 int mstSet[V]; //用于存储已经被包含在最小生成树中的顶点 //初始化所有顶点的key值为无穷大,mstSet值为0,parent值为-1 for(int i = 0; i < V; i++) key[i] = INF, mstSet[i] = 0, parent[i] = -1; //将第一个顶点作为初始点 key[0] = 0; parent[0] = -1; //生成V-1个顶点的最小生成树 for(int i = 0; i < V-1; i++) { //找到未被包含在最小生成树中的最小权值的顶点 int u = minKey(key, mstSet); //将这个顶点包含在最小生成树中 mstSet[u] = 1; //更新与该顶点相邻的顶点的key值和parent值 for(int v = 0; v < V; v++) if(graph[u][v] && mstSet[v] == 0 && graph[u][v] < key[v]) parent[v] = u, key[v] = graph[u][v]; } //打印生成的最小生成树 printMST(parent, graph); } int main() { int graph[V][V] = {{0, 2, 0, 6, 0}, {2, 0, 3, 8, 5}, {0, 3, 0, 0, 7}, {6, 8, 0, 0, 9}, {0, 5, 7, 9, 0}}; primMST(graph); return 0; } ``` 在上述代码中,我们使用了一个二维数组`graph`来存储无向带权图,数组的下标表示顶点的编号,数组的值表示边的权值。在`primMST()`函数中,我们使用了三个数组`parent`、`key`和`mstSet`来存储生成树的父节点、选择最小权值的顶点和已经被包含在最小生成树中的顶点。在`minKey()`函数中,我们找到未被包含在最小生成树中的最小权值的顶点,并返回其编号。在`printMST()`函数中,我们打印生成的最小生成树的边和权值。在`main()`函数中,我们创建一个无向带权图并调用`primMST()`函数来生成最小生成树

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值