并查集在kruskal算法中应用

原创 2015年11月19日 13:27:32

    在无向图论问题中,经常需要得到图的最小生成树,用于解决这个问题有两个经典算法:kruskal和prim,前者用于稀疏图,后者用于稠密图。kruskal算法的核心思想是贪心,按照权值顺序,先选取权值最小的边,再选取权值次小的边,依此类推,直到所选边足够把所有的点连接起来,这时边数为节点数-1。但有个选边的前提,那就是待选边不能和已选边组成回路。至此,kruskal算法要解决的问题便成了图的连通分支判断问题。而并查集正是用于求解该问题的有效方法。

    并查集是一种树形数据结构,其实现是定义一个长度为N+1(N为图的节点个数)的数组,数组元素值初始化为下标,表示所有的节点都初始化为由一个单点组成的树,每个节点都是自身的祖先。那么并查集如何判断两个连通分支是否是一个连通分支(即构成回路)呢?方法就是查找两棵树的祖先,如果祖先相同,则表示这两个连通分支是一个连通分支。除了查找,并查集还有一个方法用来合并两个连通分支,实现就是把A树(连通分支)的祖先设置为B树(连通分支)的祖先,反过来也行。

    kruskal算法通过不断地选边,然后查找这条边的两个节点所在的连通分支,再合并分支,最终得到了一颗最小生成树。算法的时间复杂度为O(NlogN)。

   JAVA实现如下:

public class Kruskal {
	
	/**
	 * 查找分支中某个元素的祖先,当祖先为自身时停止查找
	 * @param x
	 * @param branch
	 * @return
	 */
	public static int find(int x,int[] branch){
		while(x!=branch[x]){
			x = branch[x];
		}
		return x;
	}
	
	/**
	 * 合并分支,设branch[a]的祖先为b
	 * @param x
	 * @param branch
	 */
	public static void join(int a,int b,int[] branch){
		branch[a]=b;
	}
	
	public static void main(String args[]){
		Scanner in=new Scanner(System.in);
		//n表示节点数,m表示边数
		int n = in.nextInt();
		int m = in.nextInt();
		Edge[] edges = new Edge[m];
		Edge edge = null;
		//读入每条边的信息
		for(int i=0;i<m;i++){
			edge = new Edge();
			edge.a = in.nextInt();
			edge.b = in.nextInt();
			edge.w = in.nextInt();
			edges[i]=edge;
		}
		in.close();
		Arrays.sort(edges);
		
		/**
		 * 并查集初始化为N个分支,每个人都是自己的祖先
		 */
		int[] branch = new int[n+1];
		for(int i=0;i<=n;i++){
			branch[i]=i;
		}
		
		int selected = 0;
		int weightTotal = 0;
		
		//无需回溯
		for(int i=0;i<m && selected<n-1;i++){
			//查找两个结点的祖先
			int rootA = find(edges[i].a,branch);
			int rootB = find(edges[i].b,branch);
			if(rootA!=rootB){
				//合并两个分支,可以把A分支的祖先设为B分支的祖先,反之亦可
				join(rootA,rootB,branch);
				weightTotal += edges[i].w;
				selected ++;
			}
		}
		
		
		System.out.println(weightTotal);
	}
}

class Edge implements Comparable<Edge>{
	public int a;
	public int b;
	public int w;
	@Override
	public int compareTo(Edge e) {
		return this.w - e.w;
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

Kruskal算法(贪心+并查集=最小生成树)

http://www.51nod.com/ Kruskal算法的高效实现需要一种称作并查集的结构。我们在这里不介绍并查集,只介绍Kruskal算法的基本思想和证明,实现留在以后讨论。 Krusk...

Kruskal算法的并查集实现

最小生成树的kruskal算法的伪代码如下 w[i]为边的权值,u[i],v[i]分别为边的端点的下标 mst为最小生成树的所有边的结合 n为顶点的个数 m为边的个数将边按权值排序w[0]...

Kruskal算法并查集和最小堆实现

Kruskal算法的基本思想是,将图中的节点分类,分成两个集合,分别表示成S和T其中S是不在生成树中的节点集合,T是在生成树中的节点集合。刚开始的时候,T中只有源节点一个节点。同时将图中的所有边按照权...
  • jzh08
  • jzh08
  • 2010年08月02日 20:06
  • 1008

图算法 最小生成树邻接表 Kruskal算法(并查集)

之前对最小生成树Prim算法进行了一定的总结,并给出了代码实现,详见:图的最小生成树,Prim实现。 一、介绍    由于忙于各类事务,在算法方面的学习有所停滞,现在将求最小生...
  • tham_
  • tham_
  • 2015年05月27日 16:52
  • 1389

Prime算法和Krustal算法(转自博客园华山大师兄)

 Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Verte...
  • LminY
  • LminY
  • 2016年01月04日 03:31
  • 3418

【贪心算法】Kruskal算法的实现与应用

问题背景假设我们有n个位置的集合V={v1, v2, …, vn},我们想在它们顶部建立一个通信网络,网络应该是连通的,即任何两个位置vi和vj之间至少存在一条路径可以相互到达。对于确定的两个位置(v...
  • hongchh
  • hongchh
  • 2016年08月14日 13:56
  • 1696

数据结构之Kruskal算法(并查集的应用)

Kruskal算法基本思想 假设G=(V,E)是连通图,将G中的边按权值从小到大的顺序排列 1、将n个顶点看成n个集合 2、按权值从大到小的顺序选择边,所选边应满足两个顶点不在同一个顶...

最小生成树----Kruskal算法&并查集

对于图寻找最小生成树 顶点v使用并查集,初始状态下所有顶点都是一个集合。 Kruskal算法描述: 取最短的边,比较是否两个顶点都在同一集合内:如果都在,则舍弃 初始化时,v长这样 ...

最小生成树Kruskal算法+并查集检查连通

/* 10 6 1 2 6 1 3 1 1 4 5 2 3 5 2 5 3 3 4 5 3 5 6 3 6 4 4 6 2 5 6 6 */ // 本例解决最小生成树问题 // 并查集来加快效率 /...

Kruskal算法的C语言实现(并查集版)

【问题】 Kruskal算法求加权连通图的最小生成树的算法。kruskal算法总共选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。注意...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:并查集在kruskal算法中应用
举报原因:
原因补充:

(最多只允许输入30个字)