package class16; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.PriorityQueue; import java.util.Set; import java.util.Stack; //undirected graph only public class Code04_Kruskal { // Union-Find Set public static class UnionFind { // key 某一个节点, value key节点往上的节点 private HashMap fatherMap; // key 某一个集合的代表节点, value key所在集合的节点个数 private HashMap sizeMap; public UnionFind() { fatherMap = new HashMap(); sizeMap = new HashMap(); } public void makeSets(Collection nodes) { fatherMap.clear(); sizeMap.clear(); for (Node node : nodes) { fatherMap.put(node, node); sizeMap.put(node, 1); } } private Node findFather(Node n) { Stack path = new Stack<>(); while(n != fatherMap.get(n)) { path.add(n); n = fatherMap.get(n); } while(!path.isEmpty()) { fatherMap.put(path.pop(), n); } return n; } public boolean isSameSet(Node a, Node b) { return findFather(a) == findFather(b); } public void union(Node a, Node b) { if (a == null || b == null) { return; } Node aDai = findFather(a); Node bDai = findFather(b); if (aDai != bDai) { int aSetSize = sizeMap.get(aDai); int bSetSize = sizeMap.get(bDai); if (aSetSize <= bSetSize) { fatherMap.put(aDai, bDai); sizeMap.put(bDai, aSetSize + bSetSize); sizeMap.remove(aDai); } else { fatherMap.put(bDai, aDai); sizeMap.put(aDai, aSetSize + bSetSize); sizeMap.remove(bDai); } } } } public static class EdgeComparator implements Comparator { @Override public int compare(Edge o1, Edge o2) { return o1.weight - o2.weight; } } public static Set kruskalMST(Graph graph) { UnionFind unionFind = new UnionFind(); unionFind.makeSets(graph.nodes.values()); // 从小的边到大的边,依次弹出,小根堆! PriorityQueue priorityQueue = new PriorityQueue<>(new EdgeComparator()); for (Edge edge : graph.edges) { // M 条边 priorityQueue.add(edge); // O(logM) } Set result = new HashSet<>(); while (!priorityQueue.isEmpty()) { // M 条边 Edge edge = priorityQueue.poll(); // O(logM) if (!unionFind.isSameSet(edge.from, edge.to)) { // O(1) result.add(edge); unionFind.union(edge.from, edge.to); } } return result; } }