最小生成树Prim算法笔记(C语言实现)

最小生成树Prim算法笔记(C语言实现)

最小生成树书上的定义是:一个无向图G点最小生成树就的由该图的那些链接G的所有顶点的边构成的树,且总价值最低

所以,一个最小生成树,要具有原图的所有顶点,且这些顶点用一种方法连接起来,所有边的和具有最小的权值。

一个图:在这里插入图片描述
它的最小生成树:
在这里插入图片描述

现在来看如何由Prim算法得到最小生成树

首先,把所有的边都去掉,把这个图上所有的点组成一个点集。可以任选一个初始点(这里选择第1个点作为初始点)。
在这里插入图片描述
在到与1相连的边里面,找一个权值最小的:
显然,在与1相连的2,4,1中1是最小的;所以1与4相连,把他们看成一个整体
在这里插入图片描述
再继续找与1——4这一个整体相连的权值最小的边:
//这里(1——2),(4——3)都是目前最小边,但他们添加进整体的顺序并不会影响最小生成树的结构(可能是因为这两条边没有连接同一个点),有些情况下一次添加时,如果有有多条最小边的,可能导致最小生成树发生变化。希望路过的大神可以解释一下。
发现有(1——2)是里面最小的,于是把2添加进来:
在这里插入图片描述
于是把(2——1——4)看成一个整体,继续从外部找与这个整体相连的边的最小的权值;
注意:这里是从外部找,所以(2——4)这一条边是不可以连接的,(1——2——4)是一个整体
所以,此时最小是(3——4)这一条边,继续添加进来,此时的生成树就变成了:
在这里插入图片描述
继续按照上面的思路执行下去:
在这里插入图片描述
继续下一个:
在这里插入图片描述
继续下一个:
在这里插入图片描述
这样就得到了了开头的最小生成树。

分享一下代码实现的思路:(图的结构由散列表来储存)

  1. 确定一个初始点,把他成一个整体
  2. 找到与这个整体相连的权值最小的的边,和与这个边相连的点
  3. 把这个点与原整体连接起来,看成一个新的整体

重复2,3步,直到将所有顶点添加进来。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct node;
typedef struct node * pNode;
struct node{
	int num;
	int power;
	pNode next;
};
struct item{
	int key;
	int power;
	int father; 
	int k2;
};
void hashAdd(pNode,pNode);
void show(pNode *,int);
int main()
{
	pNode * list1;
	int i,a,b,j,N;
	pNode current,temp;
	puts("input the number of element:");
	scanf("%d",&N);
	list1=(pNode *)malloc(sizeof(pNode)*N);
	for(i=0;i<N;i++){
		printf("Enter the element connected to the %d element",i+1);
		list1[i]=(pNode)malloc(sizeof(struct node));
		temp=list1[i];
		temp->next=NULL;
		temp->num=i+1;
		while(scanf("%d",&a)==1){
			current=(pNode)malloc(sizeof(struct node));
			current->num=a;
			scanf("%d",&b);
			current->power=b;
			current->next=NULL;
			temp->next=current;
			temp=current;
		}
		getchar();
	}
	show(list1,N);
	//创建一个新的哈希表,用来储存新的生成子树; 
	pNode *list2;
	list2=(pNode *)malloc(sizeof(struct node)*N);//list2来储存最小生成树 
	struct item dist[N];
	for(i=0;i<N;i++){
		dist[i].key=0;
		dist[i].power=1000;
		dist[i].father=1000;
		dist[i].k2=0;
	}
	for(i=0;i<N;i++){
		list2[i]=(pNode)malloc(sizeof(struct node));
		list2[i]->num=i+1;
		list2[i]->next=NULL;
	}
	dist[0].key=1;
	pNode current1,current2;
	int min,minPower,father;
	static int Z=1;
	do{
		for(i=0;i<N;i++){ //先将目前点集外最小权值添加到数组 
			if(dist[i].key==1){//添加第i个点 
				current=list1[i]->next;
				while(current!=NULL){
					if(dist[current->num-1].key==0&&dist[current->num-1].power>current->power){
						dist[current->num-1].power=current->power;
						dist[current->num-1].father=i+1;
						
						dist[current->num-1].k2=1;
					}
					current=current->next;
				}
			} 
		}
		//元素添加进数组完成,找到最小的 
		puts("ss");
		min=1;
		minPower=dist[0].power;
		for(i=1;i<N;i++){
			if(dist[i].k2==1&&dist[i].power<minPower)
			{
				min=i+1;
				minPower=dist[i].power;
				father=dist[i].father;
			}
		}
		//成功找到最小元素,添加进新的哈希图 ,最小的是min,权值是minPower,与他相连的数是father
		dist[min-1].key=1; //正式入队 
		current1=(pNode)malloc(sizeof(struct node));
		current2=(pNode)malloc(sizeof(struct node));
		current1->num=min;
		current1->power=minPower;
		current2->num=father;
		current2->power=minPower;
		hashAdd(list2[father-1],current1);
		hashAdd(list2[min-1],current2);
		Z++;
		for(i=0;i<N;i++){ //重置一下 k2,目的是将k2加入到整体中,将他与外部分开 
		dist[i].power=1000;
		dist[i].father=1000;
		dist[i].k2=0;
	}
	}while(Z<N);
	show(list2,N);
}
void hashAdd(pNode head,pNode current)
{
	pNode temp=head;
	while(temp->next!=NULL)
		temp=temp->next;
	temp->next=current;
	current->next=NULL;
}
void show(pNode *list,int N)
{
	int i;
	pNode current;
	for(i=0;i<N;i++)
	{
		printf("%d -> ",list[i]->num);
		current=list[i]->next;
		while(current!=NULL){
			printf("%d(%d) ",current->num,current->power);
			current=current->next;
		}
		printf("\n");
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值