有点混乱的普里姆算法求最小生成树

在这里插入图片描述

Graph.h

#pragma once
//邻接矩阵的创建
#include<stdio.h>
#include <stdlib.h>  
#include<assert.h>
#include<string.h>
#include<stdbool.h>
#include<limits.h>
#define MAX 100
#define INF INT_MAX
typedef struct Graph
{
	int n;//顶点数
	char vertex[MAX];//用字符数组来存储顶点
	int edges[MAX][MAX];//邻接矩阵,存储边的权值。
	//(因为为无向带权图,若为自身则权值设为0,相互之间则设为权值,无边的话就设为无穷)
}Graph;


//声明
//获取给出字符(串)其所在顶点集(数组)的下标
int get_pos(Graph* g, char ch);
//图的创建
void CreateGraph(Graph*& G,int n);
// 输出图的邻接矩阵
void PrintGraph(Graph * g);
//图的销毁
void DestroyGraph(Graph* g);


functions.cpp

#include"Graph.h"
//获取给出字符(串)其所在顶点集(数组)的下标
int get_pos(Graph* g,char ch)
{
	for (int i = 0; i < g->n; i++)
	{
		if (ch==g->vertex[i])
		{
			return i;
		}
	}
	return -1;
}

//图的创建
void CreateGraph(Graph*&G,int n)//n为顶点数
{
	G= (Graph*)malloc(sizeof(Graph));
	assert(G);//判断是否成功开辟空间
	G->n = n;
	for (int i = 0; i < G->n; i++)
	{
		for (int j = 0; j < G->n; j++)
		{
			if (i == j)
			{
				G->edges[i][j] = 0;
				G->edges[j][i] = 0;
			}
			else//一开始默认全都是相互之间没有边
			{
				G->edges[i][j] = INF;
				G->edges[j][i] = INF;
			}
		}
	}
	
}
//输出图的邻接矩阵
void PrintGraph(Graph* g)
{
	for (int i = 0; i < g->n; i++)
	{
		printf("\t%c", g->vertex[i]);
	}
	printf("\n");
	for (int i = 0; i < g->n; i++)
	{
		printf("%c\t", g->vertex[i]);
		for (int j = 0; j < g->n; j++)
		{
			if (g->edges[i][j] == INF)
			{
				printf("∞\t");
				continue;
			}
			printf("%d\t", g->edges[i][j]);
		}
		printf("\n");
	}
}
//图的销毁
void DestroyGraph(Graph* g)
{
	free(g);
}

算法

#include"Graph.h"
//无向带权图
//#########(普里姆算法求最小生成树)#################
//返回最小权值邻接边的点的下标
int minKey(int key[], int mstSet[], Graph* G)//key数组是用来存最小边权值的数组
//mstSet 是在普里姆(Prim)算法中使用的一个辅助数组,全称可以理解为 "Minimum Spanning Tree Set",即“最小生成树集合”
{
	int min = INF;
	int min_index = 0;//用于记录邻接最小权值边终点的下标
	for (int i = 0; i < G->n; i++)
	{
		if (mstSet[i] == 0 && key[i] < min)
			//如果该点没有被加入最小生成树集合并且存在边的话则将其边权值赋给min并且将其下标赋给min_index
		{
			min = key[i];
			min_index = i;
		}
	}
	return min_index;
}
//打印最小生成树
void PrintMST(int parent[], Graph* G)
{
	printf("最小生成树构成:\n");
	for (int i = 1; i < G->n; i++)//i要从1开始,因为第一个顶点没有前驱节点
	{
		printf("边<%c,%c>权为:%d\n", G->vertex[parent[i]], G->vertex[i], G->edges[parent[i]][i]);
	}
}
//打印最小生成树
void PrintMST2(int parent[], Graph* G,int sequence[])
{
	printf("最小生成树构成:\n");
	for (int i = 0; i < G->n-1; i++)//这里是要小于n-1,因为sequence里有n-1个节点
	{
		printf("边<%c,%c>权为:%d\n", G->vertex[parent[sequence[i]]],G->vertex[sequence[i]],G->edges[parent[sequence[i]]][sequence[i]]);
	}
}
//完整普里姆算法
void PrimMST(Graph* G)
{
	int parent[MAX] = {0};//用于记录最小生成树的路径
	int key[MAX];
	int mstSet[MAX];
	//先初始化好key数组和mstSet数组
	for (int i = 0; i < G->n; i++)
	{
		key[i] = INF;
		mstSet[i] =0;//均设为0表示均未被加入最小生成树集合
	}
	//一开始都做好了初始化,但为了能达到循环进行的目的要先对第一个点进行特殊处理
	key[0] = 0;// 从顶点0开始构造最小生成树
	parent[0] = -1;//因为最小生成树的第一个顶点没有父母节点
	int sequence[MAX];//用于记录顺序
	int j = 0;
	int n = 0;//n用于计数
	for (int i = 0; i < G->n-1; i++)
		//i用于循环控制次数,条件为小于顶点数减一,因为每次处理都可简化为存父节点和找邻接最小边,而最小生成树是前n-1个顶点为父节点
	{
		int u = minKey(key, mstSet, G);//u用于存储邻接最小边点的下标
		mstSet[u] = 1;//将该点标记为已加入最小生成树集中
		n++;
		if (u != 0)
		{
			sequence[j++] = u;
		}
		//找下一个邻接最小权值边的顶点,设好其前驱节点即 // 更新相邻顶点的key值和parent值
		for (int i = 0; i < G->n; i++)
		{
			if (G->edges[u][i] && mstSet[i] == 0 && G->edges[u][i] < key[i])
				//若边不是指向自身并且点没有被加入到最小生成树集合中并且存在边
			{//则设好其父母结点并将边权值赋值给key[i]
				parent[i] = u;
				key[i] = G->edges[u][i];//赋值好所有相邻边的权值
			}
 		}
	}
	//这部分用于判断哪个顶点不存在于sequence数组中,把它找出来,就是最后一个顶点。再加入到sequence中
	int temp;
	int flag = 0;
	for (int i = 1; i < G->n; i++)
	{
		int n = 0;
		for (int j = 0; j < G->n - 1; j++)
		{
			if (sequence[j] == i)
			{
				break;
			}
			else
			{
				n++;
			}
			if (n == G->n - 1)
			{
				temp = i;
				flag = 1;
				break;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
	sequence[j] = temp;
	
	//把最小生成树的最后一个结点加入到顺序数组中
	PrintMST2(parent, G,sequence);
}


 int main(int argc, char* argv[])
{
	Graph*G;
	CreateGraph(G,7);
	char V[8] = "ABCDEFG";
	for (int i = 0; i < G->n; i++)
	{
		G->vertex[i] = V[i];//将顶点存进图中
	}
	G->edges[get_pos(G, 'A')][get_pos(G, 'B')] = 50;
	G->edges[get_pos(G, 'B')][get_pos(G, 'A')] = 50;
	G->edges[get_pos(G, 'B')][get_pos(G, 'D')] = 65;
	G->edges[get_pos(G, 'D')][get_pos(G, 'B')] = 65;
	G->edges[get_pos(G, 'A')][get_pos(G, 'C')] = 60;
	G->edges[get_pos(G, 'C')][get_pos(G, 'A')] = 60;
	G->edges[get_pos(G, 'C')][get_pos(G, 'D')] = 52;
	G->edges[get_pos(G, 'D')][get_pos(G, 'C')] = 52;
	G->edges[get_pos(G, 'D')][get_pos(G, 'G')] = 42;
	G->edges[get_pos(G, 'G')][get_pos(G, 'D')] = 42;
	G->edges[get_pos(G, 'C')][get_pos(G, 'G')] = 45;
	G->edges[get_pos(G, 'G')][get_pos(G, 'C')] = 45;
	G->edges[get_pos(G, 'B')][get_pos(G, 'E')] = 40;
	G->edges[get_pos(G, 'E')][get_pos(G, 'B')] = 40;
	G->edges[get_pos(G, 'D')][get_pos(G, 'E')] = 50;
	G->edges[get_pos(G, 'E')][get_pos(G, 'D')] = 50;
	G->edges[get_pos(G, 'D')][get_pos(G, 'F')] = 30;
	G->edges[get_pos(G, 'F')][get_pos(G, 'D')] = 30;
	G->edges[get_pos(G, 'E')][get_pos(G, 'F')] = 70;
	G->edges[get_pos(G, 'F')][get_pos(G, 'E')] = 70;
	PrintGraph(G);
	PrimMST(G);
	DestroyGraph(G);
	return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值