資料結構與演算法分析(Java語言描述)(32)—— 使用 Kruskal 演算法求有權圖的最小生成樹
阿新 • • 發佈:2019-02-20
將圖中的所有邊存到最小堆中
當最小堆非空
取出權重最小的邊
如果此邊的兩個端點是連線的
跳出本次迴圈
將此邊加入 mst 中
在並查集中 union 此邊的兩端點
package com.dataStructure.weight_graph;
import com.dataStructure.heap.MinHeap;
import com.dataStructure.union_find.UnionFind5;
import java.util.ArrayList;
import java.util.List;
// Kruskal演算法求最小生成樹
public class KruskalMST {
private List<Edge> mst; // 存放最小生成樹的邊
private Number mstWeight; // 最小生成樹的權重
// 建構函式
public KruskalMST(WeightedGraph graph) {
// 初始化私有欄位
mst = new ArrayList<>();
mstWeight = 0;
// 最小堆存放圖中所有的邊
MinHeap<Edge> edgeMinHeap = new MinHeap<>(graph.E());
for (int i = 0; i < graph.V(); i++)
for (Edge edge : graph.adjacentNode(i)) // 遍歷 i 的鄰接節點
if (edge.getV() <= edge.getW()) // 過濾掉 7-1 這種重複的邊
edgeMinHeap.insert(edge); // 將非重複的邊插入最小堆中
// 初始化一個圖中節點數量大小的並查集
UnionFind5 unionFind = new UnionFind5(graph.V());
// 當最小堆非空 且 最小生成樹尚未連線圖中的所有節點
while (!edgeMinHeap.isEmpty() && mst.size() < graph.V() - 1) {
Edge edge = edgeMinHeap.extractMin(); // 取出權重最小的邊
// 如果向 mst 中加入 edge 前,v 和 w 已經連線
// edge 加入 mst 後,將形成環,為防止形成環,跳出此次迴圈
if (unionFind.isConnected(edge.getV(), edge.getW()))
continue;
mst.add(edge); // 將 edge 加入 mst 中
unionFind.unionElements(edge.getV(), edge.getW()); // 並查集中 union v 和 w
}
for (Edge edge : mst) // 計算最小生成樹的權重
mstWeight = mstWeight.doubleValue() + edge.getWeight().doubleValue();
}
public List<Edge> getMst() {
return mst;
}
public Number getMstWeight() {
return mstWeight;
}
// 測試 Kruskal
public static void main(String[] args) {
String filename = "/testG1.txt";
int V = 8;
SparseGraph g = new SparseGraph(V, false);
ReadWeightedGraph readGraph = new ReadWeightedGraph(g, filename);
// Test Kruskal
System.out.println("Test Kruskal: ");
KruskalMST kruskalMST = new KruskalMST(g);
List<Edge> mst = kruskalMST.getMst();
for (int i = 0; i < mst.size(); i++)
System.out.println(mst.get(i));
System.out.println("The MST weight is: " + kruskalMST.getMstWeight());
System.out.println();
}
}
//public class KruskalMST {
//
// private List<Edge> mst; // 最小生成樹所包含的所有邊
// private Number mstWeight; // 最小生成樹的權值
//
// // 建構函式, 使用Kruskal演算法計算graph的最小生成樹
// public KruskalMST(WeightedGraph graph) {
// mstWeight = 0;
// mst = new ArrayList<>();
//
// // 將圖中的所有邊存放到一個最小堆中
// MinHeap<Edge> pq = new MinHeap<>(graph.E());
// for (int i = 0; i < graph.V(); i++)
// for (Edge edge : graph.adjacentNode(i))
// if (edge.getV() <= edge.getW()) // 過濾掉 7-1 等情況,防止堆中的邊重複
// pq.insert(edge);
//
//
// // 建立一個並查集, 來檢視已經訪問的節點的聯通情況
// UnionFind5 unionFind = new UnionFind5(graph.V());
// while (!pq.isEmpty() && mst.size() < graph.V() - 1) {
//
// // 從最小堆中依次從小到大取出所有的邊
// Edge e = pq.extractMin();
//
// // 如果該邊的兩個端點是聯通的, 說明加入這條邊將產生環, 扔掉這條邊
// if (unionFind.isConnected(e.getV(), e.getW()))
// continue;
//
// // 否則, 將這條邊新增進最小生成樹, 同時標記邊的兩個端點聯通
// mst.add(e);
// unionFind.unionElements(e.getV(), e.getW());
// }
//
// for (Edge edge : mst) // 計算最小生成樹的權重
// mstWeight = mstWeight.doubleValue() + edge.getWeight().doubleValue();
// }
//
// // 返回最小生成樹的所有邊
// List<Edge> mstEdges() {
// return mst;
// }
//
// // 返回最小生成樹的權值
// Number result() {
// return mstWeight;
// }
//
//
// // 測試 Kruskal
// public static void main(String[] args) {
//
// String filename = "/testG1.txt";
// int V = 8;
//
// SparseGraph g = new SparseGraph(V, false);
// ReadWeightedGraph readGraph = new ReadWeightedGraph(g, filename);
//
// // Test Kruskal
// System.out.println("Test Kruskal:");
// KruskalMST kruskalMST = new KruskalMST(g);
// List<Edge> mst = kruskalMST.mstEdges();
// for (int i = 0; i < mst.size(); i++)
// System.out.println(mst.get(i));
// System.out.println("The MST weight is: " + kruskalMST.result());
//
// System.out.println();
// }
//}