Prim算法解读

Prim算法解读及其问题

Prim算法用于构造最小生成树,初始时从图中任选一顶点加入最小生成树T中,此时树中只有一个顶点,之后选择一个与当前的最小生成树T中所有的顶点集合距离最近的一个顶点,并将该顶点和相应的边加入到T中,重复此操作,最终直至图中所有顶点加入到T中,此时T为整个图的最小生成树。

算法思想:

将图中的顶点分为两个集合,一个是已经加入到树T中的集合,一个是还未加入到T中的集合,那么我们要解决的几个问题有:

①:用什么存储树T中的顶点集合以及边集合

②:如何判断未加入到树T中的顶点哪一个是距离已加入树T中的顶点集合最近的那一个点

问题解决

若是只求最小生成树的边权之和,则可以简便许多,可以设立一个visited[vexnum]数组来判断图中的顶点是否被加入到树T中,一个d[vexnum]来存储当前每个点距离集合的最短距离。

初始情况下树为空,d数组中除要加入的初始结点距离设为0外每个数都设为极大(证明无路径可通过),加入初始结点后,循环一次图中结点,若图中结点未被访问过且能通往初始结点则将d中的数值改为图中的边权值,之后的每一次加入结点都对新结点进行判断,如此即可保证d中的数值为距离树T集合中最近的点。构造完成后,d中的所有值加起来即为边权值之和。

如图

若想完整构造一棵树,则可以使用数据结构进行存储,在对d进行修改时也对node进行修改,使node存储边连接的另外一个结点,如此可根据这两个数组找到图中对应的每一条边。

typedef struct{
    int *d[vexnum];
    int *node[vexnum];
}

代码测试

#define Inf 100

typedef struct {
	int Vex[5];
	int Edge[5][5];
	int vexnum, arcnum;
}Graph;   //测试用矩阵

Graph initialG()
{
	Graph G;
	G.vexnum = 5;
	G.arcnum = 6;
	for (int i = 0; i < 5; i++)
	{
		G.Vex[i] = i;
	}
	G.Edge[0][1] = 2;
	G.Edge[0][2] = 3;
	G.Edge[0][4] = 6;
	G.Edge[1][0] = 2;
	G.Edge[1][3] = 5;
	G.Edge[2][0] = 3;
	G.Edge[2][3] = 4;
	G.Edge[3][1] = 5;
	G.Edge[3][2] = 4;
	G.Edge[3][4] = 7;
	G.Edge[4][0] = 6;
	G.Edge[4][3] = 7;
	return G;
}

int prim(Graph G,int v)  //prim算法,用于求最小生成树的权值之和
{
	int k = G.vexnum;
	int visited[5];         //判定顶点是否被访问的数组
	for (int i = 0; i < 5; i++)
	{
		visited[i] = 0;     //0表示未被访问过
	}
	int arcs = 0;     //用于存储权值之和
	int d[5];    //用于存储距离集合的最短距离,将无限距离设为100
	for (int i = 0; i < 5; i++)
	{
		if (i == v)
			d[i] = 0;
		else
		{
			d[i] = Inf;   //Inf即无穷大目前无法到达
		}
	}
	while(1)
	{
		int min = Inf;
		int k = -1;     //每次加入的顶点值
		for (int j = 0; j < 5; j++)
		{
			if (d[j] < min && visited[j] == 0)
			{
				min = d[j];
				k = j;
			}
		}
		if (k != -1)
		{
			arcs = arcs + d[k];
			visited[k] = 1;       //1表示已被访问
			for (int p = 0; p < 5; p++)
			{
				if (G.Edge[k][p] < d[p] &&G.Edge[k][p]>0&& visited[p] == 0)
					d[p] = G.Edge[k][p];                     //将当前距离集合最短的边筛选出来
			}
		}
		else
		{
			break;
		}
	}
	return arcs;
}

int main()
{
	Graph G = initialG();
	printf("最小生成树权值之和为%d", prim(G, 0));
}

测试结果

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值