普里姆算法_最小代价生成树_邻接矩阵表示法

基本思想:
最小生成树问题的概念—普里姆算法是从点的角度来解决。若在解决问题过程中需要遍历图的所有点,则普里姆算法更好。
普里姆算法更像构建一棵树。联想我们构建二叉树的过程,从根节点出发,构建左右子树,再以左右子树为根节点,构建它们的左右子树。普里姆算法设一个点集V,初始时只有源点,从点集的点出发遍历所有以它们为起点的边,找到其中权值最小的边,且这条边的终点不在点集V中,然后将终点加入点集,再从点集V中的所有点出发,找一条权重最小的边。从点集中的点向外发散,构建起最小生成树。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
该算法事件关键步骤数为
(n+n^2)*n/2 n为图中的结点数量
事件复杂度为O(n^3)

#include<stdio.h>
#include<stdlib.h>
#define MaxVertices 100
#define MaxNum 100
#define TRUE 1
#define FALSE 0
typedef struct graph {
	int NoEdge;
	int Vertices;
	int** A;
}Graph;
void CreateGraph(Graph* g, int n, int noedge) {
	int i, j;
	g->NoEdge = noedge;
	g->Vertices = n;
	g->A = (int**)malloc(n * sizeof(int*));
	for (i = 0; i < n; i++) {
		g->A[i] = (int*)malloc(n * sizeof(sizeof(int)));
		for (j = 0; j < n; j++) {
			g->A[i][j] = noedge;
		}
		g->A[i][i] = 0;
	}
}
void Add(Graph* g, int u, int v, int w) {
	if (u < 0 || v < 0 || u > g->Vertices - 1 || v>g->Vertices - 1 || u == v || g->A[u][v] != g->NoEdge) {
		printf("BadInput\n");
	}
	else {
		g->A[u][v] = w;
	}
}
void Delete(Graph* g, int u, int v) {
	if (u < 0 || v < 0 || u > g->Vertices - 1 || v>g->Vertices - 1 || u == v || g->A[u][v] == g->NoEdge) {
		printf("BadInput\n");
	}
	else {
		g->A[u][v] = g->NoEdge;
		printf("Delete Successfully\n");
	}
}
void Exist(Graph* g, int u, int v) {
	if (u < 0 || v < 0 || u > g->Vertices - 1 || v>g->Vertices - 1 || u == v || g->A[u][v] == g->NoEdge) {
		printf("No Existance\n");
	}
	else {
		printf("Element Exists!\n");
	}
}
void Prim(Graph* g) {
	int i,b, c, v, 
		n = g->Vertices,  count = -1,
		* gatheredTreeNodes,
		tempEnd, tempStart, tempMinW,
		* currentMinCostList, * currentEndList, * currentStartList,
		* endNodesList , * minCostList,  * startNodesList, stopWhile;
	int mark[MaxVertices];

	endNodesList = (int*)malloc(n * sizeof(int));
	minCostList = (int*)malloc(n * sizeof(int));
	startNodesList = (int*)malloc(n * sizeof(int));
	gatheredTreeNodes = (int*)malloc(n * sizeof(int));
	currentMinCostList = (int*)malloc(n * sizeof(int));
	currentEndList = (int*)malloc(n * sizeof(int));
	currentStartList = (int*)malloc(n * sizeof(int));
	
	for (i = 0; i < n; i++) {
		startNodesList[i] = -1;
		endNodesList[i] = -1;
		mark[i] = FALSE;
		minCostList[i] = MaxNum;
	}
	mark[0] = TRUE;
	minCostList[0] = 0; endNodesList[0] = 0; startNodesList[0] = 0;
	count++;
	gatheredTreeNodes[count] = 0;
	while (1) {
		stopWhile = TRUE;
		for (i = 0; i < n; i++)
		{
			if (mark[i] == FALSE)
			{
				stopWhile = FALSE;
			}
		}
		if (stopWhile == TRUE) {
			break;
		}
		tempMinW = 10000;
		for (c = 0; c <= count; c++) {
			for (v = 0; v < n; v++) {
				if (g->A[gatheredTreeNodes[c]][v] != 0 
					&& g->A[gatheredTreeNodes[c]][v] != g->NoEdge 
					&& mark[v] == FALSE) {
					if (g->A[gatheredTreeNodes[c]][v] < tempMinW)
					{
						tempMinW = g->A[gatheredTreeNodes[c]][v];
						tempEnd = v;
						tempStart = gatheredTreeNodes[c];
					}
				}
			}
			if (tempMinW != 10000) {
				currentMinCostList[c] = tempMinW;
				currentEndList[c] = tempEnd;
				currentStartList[c] = tempStart;
				tempMinW = 10000;
			}
			else {
				currentMinCostList[c] = tempMinW;
			}
		}
		tempMinW = currentMinCostList[0];
		tempEnd = currentEndList[0];
		tempStart = currentStartList[0];
		for (c = 0; c <= count; c++) {
			if (currentMinCostList[c] < tempMinW) {
				tempMinW = currentMinCostList[c];
				tempEnd = currentEndList[c];
				tempStart = currentStartList[c];
			}
		}
		if (tempMinW == 10000) {
			break;
		}
		endNodesList[tempEnd] = tempEnd;
		minCostList[tempEnd] = tempMinW;
		startNodesList[tempEnd] = tempStart;
		count++;
		gatheredTreeNodes[count] = tempEnd;
		mark[tempEnd] = TRUE;
	}
	for (b = 1; b < n; b++) {
		printf("%-6d %-6d%-6d\n", startNodesList[b], minCostList[b], endNodesList[b]);
	}
}
void PrintMatrix(Graph* g) {
	int i, j;
	for (i = 0; i < g->Vertices; i++) {
		for (j = 0; j < g->Vertices; j++) {
			printf("%-4d", g->A[i][j]);
		}
		printf("\n");
	}
	printf("***************\n");
}
void main() {
	Graph* g;
	g = (Graph*)malloc(sizeof(Graph));
	CreateGraph(g, 6, -1);
	PrintMatrix(g);
	/*Add(g, 0, 2, 7);
	Add(g, 0, 4, 7);
	Add(g, 1, 2, 5);
	Add(g, 1, 5, 6);
	Add(g, 2, 0, 7);
	Add(g, 2, 1, 5);
	Add(g, 2, 3, 1);
	Add(g, 2, 5, 2);
	Add(g, 3, 2, 1);
	Add(g, 3, 5, 2);
	Add(g, 4, 0, 9);
	Add(g, 4, 5, 1);
	Add(g, 5, 1, 6);
	Add(g, 5, 2, 2);
	Add(g, 5, 3, 2);
	Add(g, 5, 4, 1);*/
	//Delete(g, 1, 0);
	Add(g, 0, 3, 5);
	Add(g, 0, 2, 1);
	Add(g, 0, 1, 6);
	Add(g, 1, 4, 3);
	Add(g, 1, 2, 5);
	Add(g, 1, 0, 6);
	Add(g, 2, 4, 6);
	Add(g, 2, 3, 5);
	Add(g, 2, 1, 5);
	Add(g, 2, 5, 4);
	Add(g, 2, 0, 1);
	Add(g, 3, 2, 5);
	Add(g, 3, 0, 5);
	Add(g, 3, 5, 2);
	Add(g, 4, 5, 6);
	Add(g, 4, 2, 6);
	Add(g, 4, 1, 3);
	Add(g, 5, 4, 6);
	Add(g, 5, 2, 4);
	Add(g, 5, 3, 2);
	PrintMatrix(g);
	Prim(g);
}

0 -1 -1 -1 -1 -1
-1 0 -1 -1 -1 -1
-1 -1 0 -1 -1 -1
-1 -1 -1 0 -1 -1
-1 -1 -1 -1 0 -1
-1 -1 -1 -1 -1 0


0 6 1 5 -1 -1
6 0 5 -1 3 -1
1 5 0 5 6 4
5 -1 5 0 -1 2
-1 3 6 -1 0 6
-1 -1 4 2 6 0


2 5 1
0 1 2
5 2 3
1 3 4
2 4 5

C:\C程序&C语言数据结构\C语言数据结构_从入门到入坑\10\邻接矩阵实现Prim算法\Debug\邻接矩阵实现Prim算法.exe (进程 9000)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
创建图邻接矩阵的步骤如下: 1. 定义一个二维数组来表示图的邻接矩阵,其中第i行第j列的值表示节点i到节点j的边权重。如果两个节点之间没有边,则该位置的值可以设置为无穷大或者一个非常大的值。 2. 初始化邻接矩阵,将所有值都设为无穷大或者一个非常大的值。 3. 遍历所有的边,将相应位置的值设置为边的权重。 下面是一个简单的示例代码: ```c #include <stdio.h> #define MAX 100 #define INF 0x7fffffff int G[MAX][MAX]; int n, m; void createGraph() { int i, j, u, v, w; scanf("%d %d", &n, &m); for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { G[i][j] = INF; } } for(i = 1; i <= m; i++) { scanf("%d %d %d", &u, &v, &w); G[u][v] = G[v][u] = w; } } ``` 接下来,我们使用普里姆算法最小生成树普里姆算法是一种贪心算法,它的基本思想是从一个任意节点开始,不断选择与当前生成树相连的最小边,直到所有的节点都被连通为止。具体步骤如下: 1. 选择一个任意节点作为起点,加入生成树中。 2. 遍历与生成树相邻的节点,找到其中权重最小的一条边,将它所连接的节点加入生成树中。 3. 重复步骤2,直到所有的节点都被加入生成树中。 下面是一个简单的示例代码: ```c void prim() { int i, j, k, min, sum = 0; int lowcost[MAX], closest[MAX]; for(i = 2; i <= n; i++) { lowcost[i] = G[1][i]; closest[i] = 1; } closest[1] = 0; for(i = 2; i <= n; i++) { min = INF; k = 0; for(j = 2; j <= n; j++) { if(closest[j] != 0 && lowcost[j] < min) { min = lowcost[j]; k = j; } } closest[k] = 0; sum += min; for(j = 2; j <= n; j++) { if(closest[j] != 0 && G[k][j] < lowcost[j]) { lowcost[j] = G[k][j]; closest[j] = k; } } } printf("最小生成树的权值之和为:%d\n", sum); } ``` 在上面的代码中,我们使用两个数组`lowcost`和`closest`来记录生成树中与每个节点相连的最小边和最近的节点。在初始化时,我们将数组`lowcost`和`closest`分别设置为节点1到其他节点的边权重和节点1。接着,我们遍历所有的节点,找到与当前生成树相邻的节点中,权重最小的一条边,并将它所连接的节点加入生成树中。接着,我们更新数组`lowcost`和`closest`中的值,继续遍历下一个节点,直到所有的节点都被加入生成树中。 完整代码如下: ```c #include <stdio.h> #define MAX 100 #define INF 0x7fffffff int G[MAX][MAX]; int n, m; void createGraph() { int i, j, u, v, w; scanf("%d %d", &n, &m); for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { G[i][j] = INF; } } for(i = 1; i <= m; i++) { scanf("%d %d %d", &u, &v, &w); G[u][v] = G[v][u] = w; } } void prim() { int i, j, k, min, sum = 0; int lowcost[MAX], closest[MAX]; for(i = 2; i <= n; i++) { lowcost[i] = G[1][i]; closest[i] = 1; } closest[1] = 0; for(i = 2; i <= n; i++) { min = INF; k = 0; for(j = 2; j <= n; j++) { if(closest[j] != 0 && lowcost[j] < min) { min = lowcost[j]; k = j; } } closest[k] = 0; sum += min; for(j = 2; j <= n; j++) { if(closest[j] != 0 && G[k][j] < lowcost[j]) { lowcost[j] = G[k][j]; closest[j] = k; } } } printf("最小生成树的权值之和为:%d\n", sum); } int main() { createGraph(); prim(); return 0; } ``` 注意,上面的代码中使用了无穷大来表示两个节点之间没有边。在实际使用时,可以根据具体情况选择一个合适的值来表示无穷大。此外,普里姆算法的时间复杂度为O(n^2),其中n为节点数。当节点数比较大时,可能需要使用更高效的算法最小生成树
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值