普里姆算法构建最小生成树

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAX 100
#define NO INT_MAX//NO表示没有边,相当于INF

typedef struct Graph
{
	int arcnum;
	int vexnum;
	char vextex[MAX][20];
	int martrix[MAX][MAX];
}Graph;
//邻接矩阵打印输出图
void print_graph(Graph* g)
{
	for (int i = 0; i < g->vexnum; i++)
	{
		printf("\t%s", g->vextex[i]);
	}
	printf("\n");
	for (int i = 0; i < g->vexnum; i++)
	{
		printf("%s\t", g->vextex[i]);
		for (int j = 0; j < g->vexnum; j++)
		{
			if (g->martrix[i][j] == INT_MAX)
			{
				printf("∞\t");
			}
			else
			{
				printf("%d\t", g->martrix[i][j]);
			}
		}
		printf("\n");
	}
}
//定义最小生成树的边结构
typedef struct Arc
{
	int begin;
	int end;
}Arc;
//打印最小生成树
void print_tree(Graph* g, Arc* arc, int count)
{
	printf("最小生成树:\n");
	for (int i = 0; i < count; i++)
	{
		printf("%s--->%s\n", g->vextex[arc[i].begin], g->vextex[arc[i].end]);
	}
}
// 普里姆算法
void graph_prim(Graph* g)
{
	int lowcost[MAX];//顶点的与其他顶点的权值
	int closest[MAX];//存储其前驱/父母结点
	//创建一个名为arc的指针,指向一个Arc类型的数组,数组的大小为g->arcnum。
	Arc* arc = (Arc*)malloc(sizeof(Arc) * g->arcnum);
	assert(arc);
	int count=0;//count用于控制存储数据进入arc数组
	//0作为最小生成树的起点
	for (int i = 0; i < g->vexnum; i++)
	{
		lowcost[i] = g->martrix[0][i];//lowcost数组用于存该点其它所有边的权值,无边则为INT_MAX
		closest[i] = 0;//先将所有顶点的前驱结点都设为第一个顶点0
	}
	printf("最小生成树的形成过程:\n");
	for (int i = 1; i < g->vexnum; i++)//注意i从1开始因为第一个顶点已经被处理了
	{
		int minweight = INT_MAX;
		int k = -1;//k用于存储邻接最小权值边的顶点下标
		for (int j = 0; j < g->vexnum; j++)
		{
			if (lowcost[j] > 0 && lowcost[j] < minweight)
	//如果边存在且顶点未被加入最小生成树顶点或不是指向自身的话(因为一般指向自身是设为0的,这里统一都设成了INT_MAX)且小于minweight
			{
				minweight = lowcost[j];//将最小权值置为该边权值
				k = j;//记录与该边邻接的顶点下标
			}
		}
		if (k != -1)
		{
			printf("边<%s,%s>权为:%d\n",g->vextex[closest[k]],g->vextex[k],minweight);
			//将这两个点存到边结构中(其实还可以做一个将权值也弄进去这个结构体的操作,但这里没有,只是存顶点)
			(arc + count)->begin = closest[k];
			(arc + count)->end = k;
			count++;
			//将lowcost数组中有关这两个权值都置为-1,表示已经加入到最小生成树权值中了(类似已访问)
			lowcost[closest[k]] = -1;
			lowcost[k] = -1;
			//更新lowcost和closest数组(找到并置好邻接更小的权值,且置好其前驱节点)
			for (int j = 0; j < g->vexnum; j++)
			{
				if (lowcost[j] != -1 && g->martrix[k][j] < lowcost[j])
			//检查当前顶点 k 到其他顶点 j 的边的权重是否小于已知的最小权重 lowcost[j]
				{
					lowcost[j] = g->martrix[k][j];//将lowcost[j] 更新为当前顶点 k 到顶点 j 的边的权重(即置好小的权值再进入下一次循环查找)
					closest[j] = k;//将 closest[j] 更新为当前顶点 k,表示顶点 j 最近的顶点是 k(相当于将k置为其前驱/parent结点)
				}
			}
		}
	}
	print_tree(g, arc, count);
	free(arc);
	arc = NULL;
}

int main()
{
	Graph g = { 10,7,{"A","B","C","D","E","F","G"},
		{
			{NO,50,60,NO,NO,NO,NO},
			{50,NO,NO,65,40,NO,NO},
			{60,NO,NO,52,NO,NO,45},
			{NO,65,52,NO,50,30,42},
			{NO,40,NO,50,NO,70,NO},
			{NO,NO,NO,30,70,NO,NO},
			{NO,NO,45,42,NO,NO,NO}
		} };
	print_graph(&g);
	graph_prim(&g);
	return 0;
}





在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值