算法导论——最小生成树:Kruskal算法(利用了并查集)

package org.loda.graph;

import org.loda.structure.MinQ;
import org.loda.structure.Queue;
import org.loda.util.In;

/**
 *
* @ClassName: KruskalMST
* @Description:Kruskal最小生成树算法
* @author minjun
* @date 2015年5月25日 下午10:50:01
*
 */
public class KruskalMST {

	private Queue<Edge> mst;

	private double weight;

	public KruskalMST(WeightGraph g){
		int v=g.v();

		mst=new Queue<Edge>();

		MinQ<Edge> q=new MinQ<Edge>();

		UF uf=new UF(v);

		//将所有边添加到优先队列中
		for(Edge edge:g.edges()){
			q.offer(edge);
		}

		while(!q.isEmpty()){
			Edge edge=q.poll();

			int a=edge.oneSide();
			int b=edge.otherSide(a);

			//如果已经连通,说明这条边无法继续加入,否则会形成环路
			if(uf.connected(a, b)) continue;

			//将两个连通分量连通
			uf.union(a, b);

			mst.enqueue(edge);

			weight+=edge.weight();
		}
	}

	/**
	 *
	* @Title: edges
	* @Description: 最小生成树的所有边
	* @param @return    设定文件
	* @return Iterable<Edge>    返回类型
	* @throws
	 */
	public Iterable<Edge> edges(){
		return mst;
	}

	/**
	 *
	* @Title: weight
	* @Description: 最小生成树的权重
	* @param @return    设定文件
	* @return double    返回类型
	* @throws
	 */
	public double weight(){
		return weight;
	}

	public static void main(String[] args) {
		In in = new In("F:\\算法\\attach\\tinyEWG.txt");
		WeightGraph g = new WeightGraph(in);
		KruskalMST m = new KruskalMST(g);
		for (Edge e : m.edges()) {
			System.out.println("边:"+e);
		}
		System.out.println(m.weight());

	}
}

所依赖的数据结构和前一篇的Prim算法相同,都是带权重边的无向图,和一条权重边,不过由于Kruskal算法的核心思想是不断找到最小的边,并查看他们连通与否,如果不连通,则合并他们成同一个连通分量,并将这条边加入到最小生成树。需要检测无向图的连通性,则需要利用到另外一个算法union-find并查集,下面给出并查集的简单实现

package org.loda.graph;

/**
 *
* @ClassName: UF
* @Description:并查集
* @author minjun
* @date 2015年5月25日 下午11:41:16
*
 */
public class UF {

	//每个元素的标识
	private int[] id;

	//连通分量数量
	private int count;

	public UF(int n){
		id=new int[n];

		//初始化为n个不相连的点(连通分量)的值
		count=n;
		for(int i=0;i<n;i++){
			id[i]=i;
		}
	}

	/**
	 *
	* @Title: connected
	* @Description: 判断两点是否连通
	* @param @param a
	* @param @param b
	* @param @return    设定文件
	* @return boolean    返回类型
	* @throws
	 */
	public boolean connected(int a,int b){
		return find(a)==find(b);
	}

	/**
	 *
	* @Title: union
	* @Description: 合并两个连通分量
	* @param @param a
	* @param @param b    设定文件
	* @return void    返回类型
	* @throws
	 */
	public void union(int a,int b){
		int A=find(a);
		int B=find(b);

		//如果相等,表示已经合并成一个连通分量了
		if(A==B) return;

		//合并所有属于b的连通分量为a
		for(int i=0;i<id.length;i++){
			if(id[i]==B)
				id[i]=A;
		}

		count--;
	}

	/**
	 *
	* @Title: find
	* @Description: 查找连通分量的值
	* @param @param a
	* @param @return    设定文件
	* @return int    返回类型
	* @throws
	 */
	public int find(int a){
		return id[a];
	}

	public int count(){
		return count;
	}

	public static void main(String[] args) {
		UF qf=new UF(10);
		qf.union(4, 3);
		qf.union(3, 8);
		qf.union(6, 5);
		qf.union(9, 4);
		qf.union(2, 1);
		qf.union(5, 0);
		qf.union(7, 2);
		qf.union(6, 1);
		qf.union(1, 0);
		qf.union(6, 7);

		System.out.println("connected :"+qf.count()+","+qf.connected(5, 9));
	}
}

输入的测试数据为:

8
16
4 5 0.35
4 7 0.37
5 7 0.28
0 7 0.16
1 5 0.32
0 4 0.38
2 3 0.17
1 7 0.19
0 2 0.26
1 2 0.36
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93

输出结果为 :

边:0-7	0.16
边:2-3	0.17
边:1-7	0.19
边:0-2	0.26
边:5-7	0.28
边:4-5	0.35
边:6-2	0.4
1.81
时间: 2024-10-03 14:46:22

算法导论——最小生成树:Kruskal算法(利用了并查集)的相关文章

算法实践--最小生成树(Kruskal算法)

什么是最小生成树(Minimum Spanning Tree) 每两个端点之间的边都有一个权重值,最小生成树是这些边的一个子集.这些边可以将所有端点连到一起,且总的权重最小 下图所示的例子,最小生成树是{cf, fa, ab} 3条边 Kruskal算法 用到上一篇中介绍的不相交集合(并查集) 首先,定义V是端点的集合,E是边的集合,A为要求的最小生成树集合 初始A为空集合,每个端点都作为单独的不相交集合 将所有边根据其权重进行排序 对每条边(v1, v2),如果其两个端点数据不同的不相交集,则

算法导论--最小生成树(Kruskal和Prim算法)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175 关于图的几个概念定义: 连通图:在无向图中,若任意两个顶点vi与vj都有路径相通,则称该无向图为连通图. 强连通图:在有向图中,若任意两个顶点vi与vj都有路径相通,则称该有向图为强连通图. 连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权:权代表着连接连个顶点的代价,称这种连通图叫做连通网. 生成树:一个连通图的生成树是

算法导论——最小生成树

对于一个连通图来说,我们可以去掉其中一些边依然保持其连通的性质,在这些图中存在一个或多个图,他们的路径总和是最小的,这样的图必然是树.因为,如果说图中存在环,则去掉环的一条边依然可以保证连通性,这与总路径和最小是矛盾的.这样的图被称为最下生成树.城市间铺设电路就可以利用最小生成树来进行规划. 如图所示的黑色路径构成了最小生成树,去掉bc并加入ah也是一棵最小生成树,可见一个图的最小生成树并不一定是唯一的. 最小生成树可以使用安全边的策略进行生成:假设集合A是最小生成树的子集,我们可以找到一条边加

SOJ4339 Driving Range 最小生成树 kruskal算法

典型的最小生成树 然后求最大的一条边 附上链接 http://cstest.scu.edu.cn/soj/problem.action?id=4339 需要注意的是有可能有 "IMPOSSIBLE" 的情况 这里用一个flag标记 记录所并的节点 只有flag = n时才能成功 负责就 "IMPOSSIBLE" 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring&g

最小生成树 kruskal算法简介

生成树--在一个图中的一个联通子图  使得所有的节点都被(访问) 最小生成树 (MST) 即联通子图的总代价(路程)最小 已知的一个图 有n个点 m条边 kruskal的算法如下 先对边从小到大排序 从最小的边起,不停的合并这条边的两个节点到一个集合,如果这条边的两个节点已经在一个集合里,则无视,否则形成回路(显然错误)直到所有的节点并到一个集合里 这里需要用到并查集来合并节点 1 int cmp(const int i,const int j) { 2 return w[i] < w[j];

最小生成树 Kruskal算法

Kruskal算法 1.概览 Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表.用来解决同样问题的还有Prim算法和Boruvka算法等.三种算法都是贪婪算法的应用.和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效. 2.算法简单描述 1).记Graph中有v个顶点,e个边 2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边 3).将原图Graph中所有e个边按权值从小到大排序 4)

无向图最小生成树Kruskal算法

问题 最小生成树的Kruskal算法 描述:有A.B.C.D四个点,每两个点之间的距离(无方向)是(第一个数字是两点之间距离,后面两个字母代表两个点):(1,'A','B'),(5,'A','C'),(3,'A','D'),(4,'B','C'),(2,'B','D'),(1,'C','D') 生成边长和最小的树,也就是找出一种连接方法,将各点连接起来,并且各点之间的距离和最小. 思路说明: Kruskal算法是经典的无向图最小生成树解决方法.此处列举两种python的实现方法.这两种方法均参考

最小生成树Kruskal算法的提出者Joseph Bernard Kruskal,Jr.

熟悉算法中的最小生成树的朋友都晓得有一个Kruskal算法,这个算法就是由题目中那个名字很长的人提出的.因为他功绩卓越,尊称他为Kruskal. Kruskal生于1928年1月29日,卒于2010年9月19日,美国人,维基里的词条中包含的头衔是:数学家.统计学家.计算机科学家.心理测量学专家. kruskal分别就读过芝加哥大学和普林斯顿大学,1954年获得博士学位. 下面链接中是一篇几年他的文章,从中可以了解他的更多成就.顺便说一句,他的父母和兄弟也都很牛. http://pan.baidu

算法8-4:Kruskal算法

Kruskal算法用于计算一个图的最小生成树.这个算法的步骤如下: 按照边的权重从小到达进行排序 依次将每条边增加到最小生成树中,除非这条边会造成回路 实现思路 第一个步骤需要对边进行排序,排序方法在之前的章节中已经介绍了很多,可以使用优先级队列进行实现,也可以使用归并排序进行实现,这里采用归并排序. 第二个步骤需要判断是否会造成回路.如果增加一条边会形成回路,那么这条边在增加之前,它两端的顶点必定是能够连通的.因此,在算法中使用并查集实现高效的判断. 代码 import java.util.L