生成树与最小生成树

生成树

对连通图进行遍历,过程中所经过的边和顶点的组合可看做是一棵普通树,通常称为生成树。
对非连通图进行遍历,过程中所经过的边和顶点的组合可看做是一个森林,通常称为生成森林。

最小生成树

由生成树的定义可知,无向连通图的生成树不是唯一的。
连通图的一次遍历所经过的边的集合及图中的所有顶点的集合就构成了该图的一颗生成树,
对连通图的不同遍历,如遍历出发点不同或储存点的顺序不同,就可能得到不同的生成树。
对于有n个顶点的无向连通图,无论其生成树的形态如何,所有生成树中都有且仅有n-1条边。

如果无向连通图是一个带权图,那么,它的所有生成树中必有一颗边的权值总和最小的生成树,称其为最小生成树

最小生成树的实现:Prim(普里姆)算法

假设G=(V,E)是一个网图,其中V是所有顶点的集合,E是所有带权边的集合。
设置两个新的集合U和T,U用于存放G的最小生成树的顶点,T用于存放G的最小生成树的边。
令U的初值为出发点,T的初值为空,Prim的思想就是在U集合中所有顶点u和V-U集合中所有顶点v选取最小权值的边(u,v)
然后将顶点v加入U中,将(u,v)加入T中,如此不断重复,直到U=V时,最小生成树构造完毕
算法思路:
	U={u},T={};
	while(U!=V){
		(u,v)=min(uv的最小权值的边|u属于U,v属于(V-U));
		T=T+{(u,v)};
		U=U+{v};
	}
代码实现:
public void Prim( Graph G,int tree[],int cost[]){
		//从v0出发,建立连通网的最小生成树
		//建立的最小生成树存于数组tree中,对应的边值在cost中
		int flag[]=new int[10];
		int k = 0,mincost;
		for (int i = 1; i < G.Vnum; i++) {
			cost[i]=G.edges[0][i];//从序号为0的v0顶点出发生成最小生成树
			tree[i]=0;
		}
		flag[0]=1;//v0进入U集合
		tree[0]=-1;//v0最小生成树的根节点,没有双亲
		for (int i = 1; i < G.Vnum; i++) {//寻找当前最小权值的边
			mincost=10000;
			for (int j = 1; j < G.Vnum; j++) {
				if (flag[j]==0&&cost[j]<mincost) {
					mincost=cost[j];
					k=j;
				}
			}
			flag[k]=1;//k进入了U集合
			for (int j = 1; j  < G.Vnum; j++) {
				if (flag[j]==0&&G.edges[k][j]<cost[j]) {
					cost[j]=G.edges[k][j];
					tree[j]=k;
				}
			}
		}
		
	}
}

最小生成树的实现:Kruskal(克鲁斯卡尔)算法

	克鲁斯卡尔算法是一种按照网中边的权值递增的顺序构造最小生成树的方法,其基本思想是:
	设无向连通网G=(V,E),令G的最小生成树为T=(Vt,Et),其初值为Vt=V,Et=空,即把所有的顶点加入进去,所有的边不加入。
	然后从E-Et中选取权值最小的边,若该边的两个顶点属于T中的两个不同的连通子图,加入该边不构成回路,
	则将此边作为最小生成树的边加入到Et中,若加入进去构成回路,则舍弃此边,选取下一条权值较小的边,
	 如此选取n-1次之后,此时连通子图即为G的最小生成树
	代码实现:
public void Kruskal(Graph G,Edge edges[],Edge T[]){
		//用克鲁斯卡尔算法构造最小生成树
		//edge中是图中各条边,且已按权值从小到大有序,最小生成树的边在T中
		int father[]=new int[100];//代表各个点的父节点
		for (int i : father) {
			father[i]=-1;
		}
		int i=0,j=0;
		int vf1,vf2;
		while(i<G.Enum&&j<G.Vnum-1){
			vf1=Find(father, edges[i].v1);
			vf2=Find(father, edges[i].v2);//寻找两个节点的父节点
			if(vf1!=vf2){//如果两点的父节点不是一个结点
				father[vf2]=vf1;//连接两点
				T[j]=edges[i];//把该边放入T中
				j++;
						
			}
			i++;
			
		}
		
	}
	public int Find(int father[],int v){
		int t=v;
		while(father[t]>=0) t=father[t];
		return t;
		
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值