C语言实现数据结构代码(四)-图-最小生成树

一、普里姆算法(找顶点

1、算法思想

    从图中任意取出一个顶点,把它当成一棵树,然后从与这棵树相接的边中选取一条最短(权值最小)的边,并将这条边及其所连接的顶点也并入这棵树中,此时得到了一棵有两个顶点的树。

    然后从与这棵树相接的边中选取一条最短的边,并将这条边及其所连顶点并入当前树中,得到一棵有3个顶点的树。

    以此类推,知道图中所有顶点都被列入树中为止,此时得到的生成树就是最小生成树。

 2、普里姆算法执行过程

从树中某个顶点v0开始,构造生成树的算法执行过程如下:

        ①将v0到其他顶点的边当作后选边;

        ②重复以下步骤n-1此,使其他n-1个顶点被并入到生成树中。

                1)从后选边中挑选出权值最小的边输出,并将与该边到另一端相接的顶点v并入树中;

                2)考察所有剩余顶点vi,如果(v,vi)的权值比lowcost[vi]小,则用(v,vi)的权值更新lowcost[vi];

3、普里姆算法代码

/*
	在用普里姆算法构建最小生成树的过程中,需要建立两个数组vset[]和lowcost[]。
		vset[i]=1表示顶点i已经被并入生成树中,vset[i] =0表示顶点i还未被并入生成树中;
		lowcost[]数组中存放当前生成树到剩余各顶点最短边的权值。 
*/ 
typedef struct{
	int no; 	//顶点编号
	char info;	//顶点其他信息 
}VertexType;	//顶点类型 

typedef struct{
	int edges[maxSize][maxSize];
	int n,e;
	VertexType vex[maxSize];
}MGraph;

void Prim(MGraph g, int v0,int &sum){
	int lowcost[maxSize],vset[maxSize],v;		//lowcost中存放的是剩余的各个顶点,距离最小生成树最小的权值。例如lowcost[2]=1.2,顶点2不在最小生成树中,那么说明顶点2距离最小生成树的最短权值为1.2 
	int i,j,k,min;					//i、j作遍历用,k存放距离最小生成树最近的顶点,min存放未入树顶点离最小生成树的最小距离 
	v=v0;
	for(i=0;i<g.n;++i){			//遍历所有顶点,初始化lowcost和vset 
		lowcost[i]=g.edgs[v0][i];
		vset[i]=0;				//入树的顶点标记为1,未入树标记为0 
	}
	vset[v0]=1;		//将v0并入树中,标记为已并入 
	sum=0;			//sum清零用来累计树的权值 
	for(i=0;i<g.n-1;++i){		//遍历未并入树的剩下的n-1个顶点 
		min=INF;		//INF是一个已经定义的比图中所有边权值都大的常量,相当于对min进行一个初始化操作 
		for(j=0;j<g.n;++j){		 
			if(vset[j]==0&&lowcost[j]<min){		//顶点j未入树,且j距离最小生成树的最小距离比 min小 
				min=lowcost[j];
				k=j;			//那么就将j顶点作为准备要入树的顶点(因为j顶点距离最小生成树最近) 
			}
		} 
		vset[k]=1;			//将顶点k入树 
		v=k;				//将v指向最新入树的顶点,接下来更新最小生成树的权值,以及lowcost(未入树顶点离最小生成树最小距离) 
		sum+=min;
		for(j=0;j<g.n;++j){
			if(vset[j]==0&&g.edges[v][j]<lowcost[j])
				lowcost[j]=g.edges[v][j];
		}
	} 
} 

二、克鲁斯卡尔算法(找边

1、算法思想

        将图中按照权值从大到小排序,然后从最小边开始扫描各边,并检测当前边是否为候选边,即是否该边的并入会构成回路,如不构成回路,则将该边并入当前生成树中,直到所有边都被检测完为止。

 

 

2、克鲁斯卡尔算法代码


typedef struct{
	int no;
	char data;
}VexType;

typedef struct{
	int edgs[maxSize][maxSize];
	int n,e;
	VexType vex[maxSize];
}MGraph;

typedef struct{
	int a,b;		//a,b为一条边所连的两个顶点
	int w;			//边的权值 
}Road; 

Road road[maxSize];
int v[maxSize];		//定义并查集数组 
int getRoot(int a){		//在查并集中查找根节点的函数 
	while(a!=v[a])
		a=v[a];
	return a;
}	

void Kruskal(MGraph g,int &sum,Road road[]){
	int i;
	int N,E,a,b;
	N=g.n;
	E=g.e;
	sum=0;
	for(i=0;i<E;++i)
		v[i]=i;
	sort(road,E);			//对road数组中的E条边按其权值从小到大排序
	for(i=0;i<E;++i){
		a=getRoot(road[i].a);
		b=getRoot(road[i].b);
		if(a!=b){
			v[a]=b;
			sum+=road[i].w;
		}
	} 
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值