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