普里姆算法(邻接矩阵)

普里姆算法(邻接矩阵)

思想

从某个顶点开始(不要把它看成一个单独的顶点,把它看成只有一个结点的子生成树)
在第一步的生成树的相邻边中,选一条最小的边,将最小的边和边的另一个结点并入子生成树中(生成树就长大了一点)
继续,直到所有的顶点都被并入了生成树

步骤

1.取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w
2.在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,
3.并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。
4.之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。

性能

O(n^2),适合稠密图(边多的图)
另一个【克鲁斯卡尔算法】O(eloge):适合稀疏图(边少的图)

举例
1.蓝色的顶点:还未考虑的顶点
2.黄色的顶点:已经考虑完的顶点
3.蓝色的线:未考虑的边
4.紫色的线:考虑范围内的边
5.红色的线:生成树的边(最短的边)
在这里插入图片描述
将a纳入考虑的顶点,变成黄色
第一步:考虑黄色顶点【a】

1.考虑与a相连的所有边(紫色的边),取出最短的边:18
2.将最短边,纳入生成树的边(变红色)
3.将顶点b纳入已考虑的顶点(变黄色)

第二步:考虑黄色的顶点【a,b】

1.考虑与a,b相连的所有边(紫色的边),取出最短的边8
2.将最短边,纳入生成树的边(变红色)
3.将顶点c纳入已考虑的顶点(变黄色)

第三步:继续考虑黄色的顶点【a,b,c】

1.考虑与a,b,c相连的所有边(紫色的边),取出最短的边20
2.将最短边,纳入生成树的边(变红色)
3.将顶点d纳入已考虑的顶点(变黄色)

最终
在这里插入图片描述

实现

记:

1.黄色的顶点,为顶点集【U】,即已落在生成树上的顶点
2.蓝色的顶点,为顶点集【V-U】,即尚未落在生成树上的顶点

设置一个辅助数组

1.下标:顶点v
2.lowcost:记录【黄色的点们】到【v】的最短边
3.adjvex:记录【黄色的点集】中哪一个顶点,到v最短

在这里插入图片描述

最小生成树

void Prim(MGraph* mgraph, int v)
{
	int i, j;
	int min, index;
	int lowcost[NUM];  //记录当前树到剩余节点的最小权值   lowcost[i] = 0 表示i在树中
	int adjvex[NUM] = { 0 };   //保存邻接节点下标数组
	adjvex[1] = 1;
	lowcost[1] = 0;      
	for (i = 2;i <= mgraph->vexnum;i++)
	{	              
			lowcost[i] = mgraph->arcs[v][i];   //将与下标为0的顶点有边的权值存入lowcost数组中
			adjvex[i] = 1;   //这些顶点的adjvex数组全部初始化为0		
	}

	for (j = 2;j <= mgraph->vexnum;j++) 
	{
		min = INT_MAX;    //需要找最小值设置一个最大值比较
		index = 1;
		for (i = 1;i <= mgraph->vexnum;i++)
		{
			if (lowcost[i] != 0 && lowcost[i] != MAX_NUM)
			{
				if (lowcost[i] < min)
				{
					min = lowcost[i];
					index = i;
				}
			}
		}
		printf("%c -> %c :%d\n", mgraph->vexs[adjvex[index]], mgraph->vexs[index], min);
		lowcost[index] = 0;  //将该顶点加入到生成树中
		for (i = 1;i <= mgraph->vexnum;i++)
		{
			if (mgraph->arcs[i][index] < lowcost[i] &&lowcost[i] != 0)
			{
				lowcost[i] = mgraph->arcs[index][i];
				adjvex[i] = index;
			}
		}
	}
}

完整代码
#include<stdio.h>
#include<stdlib.h>
#define MAX_VEX_NUM 20    //最大顶点数

#define MAX_NUM (int)1000
typedef char VertextType;
typedef enum { DG, UDG }GraphKind; //判定图的类型,有向或无向
typedef struct
{
	VertextType vexs[MAX_VEX_NUM]; //存放结点的char行数组
	int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; //存放边的数组
	int vexnum, arcnum;//结点数,边数
	GraphKind Type;//存放图的类型
}MGraph;

//索引判断
int index(char vex, MGraph* mg)
{
	int i;
	for (i = 1;i <= mg->vexnum;i++)
	{
		if (mg->vexs[i] == vex)
			return i;
	}
	return 0;

}

//生成邻接矩阵
void Creat_MG(MGraph* mg)
{
	int type, i, j, k, v1_index, v2_index ,weight = 0;
	char v1, v2;
	printf("please input graph type 0.DG 1.UDG. input nums:");
	scanf_s("%d", &type);  //输入图的类型
	if (type == 0)
		mg->Type = DG;
	else if (type == 1)
	{
		mg->Type = UDG;
	}
	else
	{
		printf("please input 0 or 1!!!");
		return;
	}
	printf("Please input vexnum:");
	scanf_s("%d", &mg->vexnum); //输入结点数
	printf("Please input arcnum:");
	scanf_s("%d", &mg->arcnum);//输入边数
	getchar();
	for (i = 1;i <= mg->vexnum;i++)
	{
		printf("please input %d vex:", i);
		scanf_s("%c", &mg->vexs[i], 1);//循环存放每个结点
		getchar();
	}
	for (i = 1;i <= mg->vexnum;i++)
		for (j = 1;j <= mg->vexnum;j++)
			mg->arcs[i][j] = MAX_NUM;//初始化边,全部设为MAX_NUM
	for (i = 1;i <= mg->vexnum;i++)
			mg->arcs[i][i] = 0;//初始化边,全部设为0
	for (k = 1;k <= mg->arcnum;k++)
	{
		printf("Please input %d arc(vex1,vex2):", k);
		scanf_s("%c %c %d", &v1, 1, &v2, 1, &weight);
		v1_index = index(v1, mg);//索引该结点对应的位置
		v2_index = index(v2, mg);//索引该结点对应的位置
		if (mg->Type == 1)//如果是无向图
		{
			mg->arcs[v1_index][v2_index] = weight;
			mg->arcs[v2_index][v1_index] = weight;//将矩阵的对应的值1
		}
		else
			mg->arcs[v1_index][v2_index] = weight;
		getchar();
	}
}
void Print_MG(MGraph* mg)
{
	int i, j;
	if (mg->Type == 0)
		printf("Is Direct Graph\n");
	else
		printf("Is UNDirect Graph\n");
	for (i = 1;i <= mg->vexnum;i++)
	{
		for (j = 1;j <= mg->vexnum;j++)
		{
			if (mg->arcs[i][j] == MAX_NUM)
			{
				printf("∞  ");
			}
			else
			{
				printf("%-4d", mg->arcs[i][j]);//遍历输出矩阵
			}
			
		}
		printf("\n");
	}
}

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "MGraph.h"

#define NUM 30
#define MAX_NUM (int)1000

void Prim(MGraph* mgraph, int v)
{
	int i, j;
	int min, index;
	int lowcost[NUM];  //记录当前树到剩余节点的最小权值   lowcost[i] = 0 表示i在树中
	int adjvex[NUM] = { 0 };   //保存邻接节点下标数组
	adjvex[1] = 1;
	lowcost[1] = 0;      
	for (i = 2;i <= mgraph->vexnum;i++)
	{	              
			lowcost[i] = mgraph->arcs[v][i];   //将与下标为0的顶点有边的权值存入lowcost数组中
			adjvex[i] = 1;   //这些顶点的adjvex数组全部初始化为0		
	}

	for (j = 2;j <= mgraph->vexnum;j++) 
	{
		min = INT_MAX;    //需要找最小值设置一个最大值比较
		index = 1;
		for (i = 1;i <= mgraph->vexnum;i++)
		{
			if (lowcost[i] != 0 && lowcost[i] != MAX_NUM)
			{
				if (lowcost[i] < min)
				{
					min = lowcost[i];
					index = i;
				}
			}
		}
		printf("%c -> %c :%d\n", mgraph->vexs[adjvex[index]], mgraph->vexs[index], min);
		lowcost[index] = 0;  //将该顶点加入到生成树中
		for (i = 1;i <= mgraph->vexnum;i++)
		{
			if (mgraph->arcs[i][index] < lowcost[i] &&lowcost[i] != 0)
			{
				lowcost[i] = mgraph->arcs[index][i];
				adjvex[i] = index;
			}
		}
	}
}

int main()
{
	MGraph MG;
	Creat_MG(&MG);
	Print_MG(&MG);
	Prim(&MG, 1);
	return 0;
}

在这里插入图片描述

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值