算法導論——最小生成樹: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並查集,下面給出並查集的簡單實現 java

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
相關文章
相關標籤/搜索