普利姆算法最小生成树--C语言

假设我们现在有一个连通图,顶点与顶点之间的边拥有权值,在保证所有顶点都在树中的情况下,使顶点之间的权值之和最小的树,就是最小生成树。

        所谓普利姆算法,就是随便取一个点,然后根据已知边的权值大小,去寻找下一个顶点的过程。例如取 0 为起始的最小树。对于 0 来说,权值最小的边是 1,所以我们把顶点 2 也纳入到最小树,在这些已知边中,4 为权值最小的边(以访问的顶点不再访问),所以把顶点 5 纳入到最小树中。

依次类推,遵循的规则就是:
1.在已知边的权值中寻找最小权值的边,并把该节点纳入到最小树中。
2.因为是树结构,所以不能有回路,也就是不能访问已经访问过的顶点。

 最后,最小树就是红色圈的边构成的树:

理解起来到没什么困难,但是代码比较抽象难理解。

        首先要明确我们的第一步:随意传进去一个顶点,找到该顶点的最小权值边,并把该边连接的顶点纳入最小树。下面的代码是准备工作,vex_weight是传入顶点的边的权值,closest_set是离传入顶点最近的顶点。由于图已经创建完成,G->arcs其实就是array。

        至于为什么让closest_set[i] = vex;是因为一开始最小生成树中只有传入的顶点没有其他顶点,后面也会讲到。

#define Max 999	表示两个顶点之间没有边相连,是断开的
    int array[6][6] = {
		0,6,1,5,Max,Max,
		6,0,5,Max,3,Max,
		1,5,0,5,6,4,
		5,Max,5,0,Max,2,
		Max,3,6,Max,0,6,
		Max,Max,4,2,6,0
	};

void Prim(Graph* G, int vex) {
	int* vex_weight = (int*)malloc(sizeof(int) * G->vexsNum);
	int* closest_set = (int*)malloc(sizeof(int) * G->vexsNum);
	int node;
	for (int i = 0; i < G->vexsNum; i++) {
		vex_weight[i] = G->arcs[vex][i];
		closest_set[i] = vex;
	}

        我们可以先写出下面的代码,第一个for循环的意思是要找 顶点数-1 次顶点,因为传入顶点已经在树中了,第二个for循环是要找到与顶点连接,权值最小的另一个顶点,并且记录下这个顶点 node,把它的权值置为 0,(表示已经加入树,例如:顶点和自身之间的权值也为 0。)最后打印。

	for (int a = 1; a < G->vexsNum; a++) {
		int min = Max;
		for (int b = 0; b < G->vexsNum; b++) {
			if (vex_weight[b] != 0 && vex_weight[b] < min) {
				min = vex_weight[b];
				node = b;
			}
		}
		vex_weight[node] = 0;
		printf("%d -> %d ,weight = %d", closest_set[node], node, min);
		printf("\n");

	}

        看似没有什么问题,但是如果传入顶点和部分顶点不相连,该怎么更新我们传入顶点呢。在这里我们可以这样做: 

        假设我们传入的是 0 这个顶点,首先按照我们上面代码的逻辑,找到最小权值边的顶点,所以把和2 顶点的权值边置为 0,表示已经把 2 顶点纳入到树中,打印完毕。那么现在请问,下次寻找应该在那些权值边中寻找最小顶点,答案是 0 和 2 顶点,那么如何更新权值呢?

 

        我们现在可以把 0 和 2 顶点看成是一个顶点,看似传入顶点和 4,5 顶点不相连,但是因为 2 顶点的存在,其实可以相连。因为 0 和 2 都在树中,我们的目的只是找到最小权值的顶点,所以更新如下:node是第一个最小权值顶点,也就是蓝色框。

		for (int j = 0; j < G->vexsNum; j++) {
			if (G->arcs[node][j] < vex_weight[j]) {
				vex_weight[j] = G->arcs[node][j];
				closest_set[j] = node;
			}
		}

更新过后,传入顶点的权值和刚纳入到最小树的权值相比较,更新权值。

那么closest_set[j] = node;是什么意思,为什么更新了最近顶点数组,这是因为,与传入顶点不相连的顶点,是通过某些顶点间接相连的。就拿刚才的例子来说,原来的最近顶点数组是这样的:

经过第一个顶点的纳入变成了:

变成 2 的位置正好对应刚才的更新权值的位置,也就是说,把 0 和 2 节点缝合了一下,把没用的较大权值删去。

接着解释,下一轮又开始权值最小的寻找,这时最小权值是 4 ,这时打印的就是 2 顶点到 5 顶点,而不是 0 顶点到 5 顶点,因为是因为纳入 2 顶点所以才和 5 顶点相连的,这就是更新顶点的作用。

我们只需要把更新代码放在打印的后面:

void Prim(Graph* G, int vex) {
	int* vex_weight = (int*)malloc(sizeof(int) * G->vexsNum);
	int* closest_set = (int*)malloc(sizeof(int) * G->vexsNum);
	int node;
	for (int i = 0; i < G->vexsNum; i++) {
		vex_weight[i] = G->arcs[vex][i];
		closest_set[i] = vex;
	}
	for (int a = 1; a < G->vexsNum; a++) {
		int min = Max;
		for (int b = 0; b < G->vexsNum; b++) {
			if (vex_weight[b] != 0 && vex_weight[b] < min) {
				min = vex_weight[b];
				node = b;
			}
		}
		vex_weight[node] = 0;
		printf("%d -> %d ,weight = %d", closest_set[node], node, min);
		printf("\n");
		for (int j = 0; j < G->vexsNum; j++) {
			if (G->arcs[node][j] < vex_weight[j]) {
				vex_weight[j] = G->arcs[node][j];
				closest_set[j] = node;
			}
		}

	}
}

这就是文章的全部内容了,希望对你有所帮助,如有错误欢迎评论。

相关推荐

  1. 算法——生成

    2024-06-09 15:32:05       11 阅读
  2. prim算法生成

    2024-06-09 15:32:05       33 阅读
  3. 生成

    2024-06-09 15:32:05       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-09 15:32:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-09 15:32:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-09 15:32:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-09 15:32:05       20 阅读

热门阅读

  1. 未来的视窗:苹果Vision Air猜想与期待

    2024-06-09 15:32:05       9 阅读
  2. vue3如何定义一个组件

    2024-06-09 15:32:05       9 阅读
  3. SQL Server(四)

    2024-06-09 15:32:05       8 阅读
  4. 数学学习基本理念与方法

    2024-06-09 15:32:05       10 阅读
  5. 看屏幕久了如何休息眼睛

    2024-06-09 15:32:05       9 阅读
  6. C++的算法:欧拉道路与欧拉回路

    2024-06-09 15:32:05       10 阅读
  7. C++细节梳理之模版

    2024-06-09 15:32:05       8 阅读