Prim算法数据结构c语言

在对无向图进行遍历时,若是连通图,仅需调用遍历过程(DFS和BFS)一次,从图中的任一顶点出发便可以遍历图中的各个顶点,若是非连通图,则需多次调用遍历过程,每次调用得到的顶点集连同相关的边就构成=了图的一个连通分量,设G=(V,E)为连通图,则从图中的任一顶点出发遍历图时必定将E(G)分成两个集合T和B,显然,G’=(V,T)是G的极小连通子图,即G’是G的一颗生成树,
由深度优先遍历得到的生成树称为深度优先生成树,相应的,由广度优先遍历得到的生成树称为广度优先生成树。
这样的生成树由遍历时访问过的n个顶点和遍历时经历的(n-1)条边组成
对于非连通图,每个连通分量中的顶点集和遍历时走过的边一起构成一颗生成树,各连通分量的生成树组成非连通图的生成森林。
prim算法是一种构造算法,可以求出从某一点开始的最小生成树,用于在加权连通图中找到最小生成树,这个算法可以从图的任意一个顶点开始,逐步扩展已经找到的生成树,直到所有顶点都被包含进来。

下面是prim算法实现

#include<stdio.h>
#include<stdlib.h>
#define MAXV 10
typedef struct {
	int n, e;
	char vexs[MAXV];
	int edgs[MAXV][MAXV];
}MatGraph;
int visited[MAXV] = { 0 };
void Create(MatGraph* G)
{
	int w, l, weight;
	scanf("%d %d", &G->n, &G->e);
	for (int i = 0; i < G->n; i++)
	{
		scanf("%c", &G->vexs[i]);
	}
	for (int i = 0; i < G->n; i++)
	{
		for (int j = 0; j < G->n; j++)
		{
			G->edgs[i][j] = 32367;
		}
	}
	for (int i = 0; i < G->e; i++)
	{
		scanf("%d %d %d", &w, &l, &weight);
		G->edgs[w][l] = G->edgs[l][w] = weight;
	}
}
void Prim(MatGraph* G, int v)
{
	int lowcost[MAXV];
	int closet[MAXV];
	int visited[MAXV] = { 0 };
	int Min = 32367, k = 0;
	for (int i = 0; i < G->n; i++)
	{
		lowcost[i] = G->edgs[v][i];//顶点集
		closet[i] = v;//边集
	}
	visited[v] = 1;
	/*lowcost数组用于确定下一步应该选择哪个顶点加入最小生成树,其实我个人觉得最好在写一个树组visited专门用来防止被重复访问,用这种要去比大小的就不太好
	closest数组用于记录每个顶点应该如何连接到已经在最小生成树中的顶点,可以通过closet得到输出结果*/
	for (int i = 1; i < G->n; i++)
	{
		Min = 32367; k = 0;
		for (int j = 0; j < G->n; j++)
		{
			if (visited[j] == 0 && lowcost[j] < Min)
			{
				Min = lowcost[j];
				k = j;
			}
		}
		printf("%c到%c的权值为%d\n", G->vexs[closet[k]], G->vexs[k], Min);//上一个顶点,这个顶点,两边之间的权值
		visited[k] = 1;
		for (int j = 0; j < G->n; j++)
		{
			if (visited[j] == 0 && G->edgs[k][j] < lowcost[j])
			{
				lowcost[j] = G->edgs[k][j];
				closet[j] = k;
			}
		}
	}

}
int main()
{
	MatGraph G;
	Create(&G);
	Prim(&G, 1);
}

这里提一下,我看有人这么写,

void Prim(MatGraph* G,int v)
{
	int lowcost[MAXV];
	int closet[MAXV];
	int visited[MAXV] = { 0 };
	int Min = 32367,k=0;
	for (int i = 0; i < G->n; i++)
	{
		lowcost[i] = G->edgs[v][i];//顶点集
		closet[i] = v;//边集
	}
	lowcost[v] = 0;
	for (int i = 1; i < G->n; i++)
	{
		Min = 32367; k = 0;
		for (int j = 0; j < G->n; j++)
		{
			if (lowcost[j] != 0 && lowcost[j] < Min)
			{
				Min = lowcost[j];
				k = j;
			}
		}
		printf("%c到%c的权值为%d\n", G->vexs[closet[k]], G->vexs[k], Min);//上一个顶点,这个顶点,两边之间的权值
		lowcost[k]=0;
		for (int j = 0; j < G->n; j++)
		{
			if (lowcost[j] != 0 && G->edgs[k][j] < lowcost[j])
			{
				lowcost[j] = G->edgs[k][j];
				closet[j] = k;
			}
		}
	}

}

这里实际是把lowcost多用了,规定lowcost等于0就是已经访问过了,这种写法有点毛病,要是有条边的权值就是0怎么办,就可能会漏掉顶点了

在这里插入图片描述
结果没错。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值