最小生成树——Prim算法

一、prim算法;

int Prim(MGraph Graph,LGraph MST)
{
	//将最小生成树保存为邻接表存储的图MST,返回最小权重
	WeightType dist[MaxVertexNum],TotalWeight;
	Vertex parent[MaxVertexNum],V,W;
	int VCount;
	Edge E;
	
	//初始化
	for(V=0;V<Graph->Nv ;V++){
		//假设V到W没有直接的边 
		dist[V]=Graph->G[0][V];
		parent[V]=0;
	} 
	TotalWeight=0;//初始化权重和
	VCount=0;//初始化收录的权重和
	//创建包含所有顶点但没有变的图(邻接表)
	MST=CreateLGraph(Graph->Nv); 
	E=(Edge) malloc(sizeof(struct ENode));
	
	//将初始点0收录进MST
	dist[0]=0;
	VCount++;
	parent[0]=-1;//当前树根是0
	while(1){
		//寻找未被收录顶点中dist最小者 
		V=FindMinDist(Graph,dist);
		if(V==ERROR)
			break;
		//将V及相应的边<parent[V],V>收录进MST
		E->V1 =parent[V];
		E->V2 =V;
		E->Weight =dist[V];
		InsertLEdge(MST,E); 
		TotalWeight+=dist[V];
		dist[V]=0;
		VCount++;
		//判断是否可以缩短路径 
		for(W=0;W<Graph->Nv ;W++)
			if(dist[W]!=0&&Graph->G[V][W]<INFINITY){
				//W是V的邻接点并且未被收录
				if(Graph->G[V][W]<dist[W]){
					//收录V使dist[V]变小
					dist[W]=Graph->G[V][W];
					parent[W]=V; 
				} 
			}
	} //while结束
	if(VCount<Graph->Nv )
		TotalWeight=ERROR;//MST中收录的顶点不到V 
	 return TotalWeight; 
 } 

 

二、完整代码:


#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

#define MaxVertexNum 100 //最大顶点数
#define INFINITY 65535 //∞设为双字节无符号整型的最大值65535
#define ERROR -1//错误标记,表示生成树不存在 
typedef int Vertex; //用顶点下标表示顶点,为整型
typedef int WeightType; //边的权值设为整型
typedef char DataType; //顶点存储的数据类型为字符型
//邻接矩阵 
/*-----------图的定义-------------*/ 
typedef struct GNode *PtrToGNode;
struct GNode{
	int Nv;//顶点数
	int Ne; //边数
	WeightType G[MaxVertexNum][MaxVertexNum]; //邻接矩阵 
	DataType Data[MaxVertexNum];//存顶点的数据 
};
typedef PtrToGNode MGraph; //以邻接矩阵存储的图的类型

/*-----------边的定义-------------*/
typedef struct ENode *PtrToENode;
struct ENode{
	Vertex V1,V2;//有向边<V1,V2>
	WeightType Weight; //权值 
};
typedef PtrToENode Edge;

//邻接表 
/*-----------邻接点的定义-------------*/
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
	Vertex AdjV;//邻接点下标
	WeightType Weight;//边的权值 
	PtrToAdjVNode Next;//指向下一个邻接点 
};

/*-----------顶点表头结点的定义-------------*/
typedef struct VNode{
	PtrToAdjVNode FirstEdge;//边表头指针
	DataType Data;//存顶点的数据
}AdjList[MaxVertexNum];//AdjList是邻接表类型

/*-----------图结点的定义-------------*/
typedef struct LGNode *LGraph;
struct LGNode{
	int Nv;//顶点数 
	int Ne;//边数 
	AdjList G;//邻接表 
};


/*-----------创建邻接矩阵-------------*/
MGraph CreateGraph(int VertexNum)
{//创建一个包含全部顶点的无边图 
	Vertex V,W;
	MGraph Graph;
	Graph=(MGraph)malloc(sizeof(struct GNode)); 
	Graph->Nv =VertexNum;
	Graph->Ne =0;
	//初始化邻接矩阵
	//顶点编号从0-Graph->Nv-1
	for(V=0;V<Graph->Nv;V++)
		for(W=0;W<Graph->Nv;W++)
			Graph->G[V][W]=INFINITY;//都为∞ 
//	PrintResult(Graph);
	return Graph; 
 } 
/*-----------创建邻接表-------------*/
LGraph CreateLGraph(int VertexNum)
{
	//初始化一个只有顶点没有边的图 
	LGraph Graph;
	Vertex V;
	Graph=(LGraph)malloc(sizeof(struct LGNode));
	Graph->Nv =VertexNum;
	Graph->Ne =0;
	//初始化邻接表头指针
	for(V=0;V<Graph->Nv ;V++)
		Graph->G[V].FirstEdge =NULL;
	return Graph;
}

/*-----------插入邻接矩阵-------------*/
void InsertEdge(MGraph Graph,Edge E)
{//逐条插入边 
	//插入边<V1,V2>
	Graph->G [E->V1 ][E->V2 ]=E->Weight ;
	//若是无向图,还需要插入边<V2,V1>
	Graph->G [E->V2 ][E->V1 ]=E->Weight ; 
}
/*-----------插入邻接表-------------*/
void InsertLEdge(LGraph Graph,Edge E)
{
	//逐条加入边
	PtrToAdjVNode NewNode;
	//插入边<V1,V2>,为V2建立新的连接点 
	NewNode =(PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
	NewNode->AdjV =E->V2 ;
	NewNode->Weight =E->Weight ;
	//将V2插入V1的表头
	NewNode->Next =Graph->G[E->V1 ].FirstEdge;
	Graph->G[E->V1 ].FirstEdge =NewNode; 
	
	//若是无向图,插入边<V2,V1>
	NewNode=(PtrToAdjVNode) malloc(sizeof(struct AdjVNode));
	NewNode->AdjV =E->V1 ;
	NewNode->Weight =E->Weight ;
//	将V1插入V2的表头
	NewNode->Next =Graph->G[E->V2 ].FirstEdge ;
	Graph->G[E->V2 ].FirstEdge =NewNode; 
	 
 } 

/*-----------读入数据创建图-------------*/
MGraph BuildGraph()
{
	MGraph Graph;
	Edge E;
	Vertex V;
	int Nv,i;
	
	printf("请输入图的顶点数:");
	scanf("%d",&Nv);
	Graph=CreateGraph(Nv);//初始化有Nv个顶点但没有边的图 
	printf("请输入边的个数:");
	scanf("%d",&(Graph->Ne));
	if(Graph->Ne !=0){//有边 
		//插入边的起点,终点,权值
		printf("请输入%d个边的起点 终点 权值:\n",Graph->Ne ); 
		E=(Edge)malloc(sizeof(struct ENode));//开辟空间 
		for(i=0;i<Graph->Ne ;i++){
			printf("%d : ",i);
			scanf("%d %d %d",&E->V1,&E->V2 ,&E->Weight );
			InsertEdge(Graph,E); 
		}
	}
	//如果顶点有数据的话,读入数据
	//for(V=0;V<Graph->Nv ;V++)
	//	scanf("%c",&(Graph->Data[V]));
	return Graph; 
}

/*---------------寻找最小dist权值----------------*/
Vertex FindMinDist(MGraph Graph,WeightType dist[])
{
	Vertex MinV,V;
	WeightType MinDist=INFINITY;
	for(V=0;V<Graph->Nv ;V++){
		if(dist[V]!=0&&dist[V]<MinDist){
			MinDist=dist[V];
			MinV=V;//更新对应点 
		}
	}
	 if(MinDist<INFINITY)//找到最小dist
	 	return MinV;//返回对应的下标 
	else return ERROR;//不存在 
 } 

/*----------------prim算法----------------*/
int Prim(MGraph Graph,LGraph MST)
{
	//将最小生成树保存为邻接表存储的图MST,返回最小权重
	WeightType dist[MaxVertexNum],TotalWeight;
	Vertex parent[MaxVertexNum],V,W;
	int VCount;
	Edge E;
	
	//初始化
	for(V=0;V<Graph->Nv ;V++){
		//假设V到W没有直接的边 
		dist[V]=Graph->G[0][V];
		parent[V]=0;
	} 
	TotalWeight=0;//初始化权重和
	VCount=0;//初始化收录的权重和
	//创建包含所有顶点但没有变的图(邻接表)
	MST=CreateLGraph(Graph->Nv); 
	E=(Edge) malloc(sizeof(struct ENode));
	
	//将初始点0收录进MST
	dist[0]=0;
	VCount++;
	parent[0]=-1;//当前树根是0
	while(1){
		//寻找未被收录顶点中dist最小者 
		V=FindMinDist(Graph,dist);
		if(V==ERROR)
			break;
		//将V及相应的边<parent[V],V>收录进MST
		E->V1 =parent[V];
		E->V2 =V;
		E->Weight =dist[V];
		InsertLEdge(MST,E); 
		TotalWeight+=dist[V];
		dist[V]=0;
		VCount++;
		//判断是否可以缩短路径 
		for(W=0;W<Graph->Nv ;W++)
			if(dist[W]!=0&&Graph->G[V][W]<INFINITY){
				//W是V的邻接点并且未被收录
				if(Graph->G[V][W]<dist[W]){
					//收录V使dist[V]变小
					dist[W]=Graph->G[V][W];
					parent[W]=V; 
				} 
			}
	} //while结束
	if(VCount<Graph->Nv )
		TotalWeight=ERROR;//MST中收录的顶点不到V 
	 return TotalWeight; 
 } 



void PrintResult(MGraph Graph)
{
	printf("邻接矩阵:\n"); 
	int V,W;
	for(V=0;V<Graph->Nv ;V++){
		for(W=0;W<Graph->Nv ;W++){
			if(Graph->G[V][W]==INFINITY)printf("∞ "); 
			else printf("%d ",Graph->G[V][W]);
		}
		printf("\n");
	}
}

int main()
{
	MGraph Graph;
	LGraph MST;
	Graph=BuildGraph();
	PrintResult(Graph);
	int TotalWeight=Prim(Graph,MST);
	printf("TotalWeight=%d\n",TotalWeight);
	
	return 0;
}


三、运行: 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值