最小生成树
最小生成树:
* 在整个图连通的情况下,保证所有边的权值之和最小,找出这个图
1.Kruskal算法:
* Kruskal算法思路:
* 将边从小到大进行排列,然后在加入边时,看边的两个端点是否已经连通,若连通,则不加这条边,直接检查下一条边
* 若不连通,则加上这条边,并把边上的点设为连通的状态.
*
* 而判断边连不连通则是看这两条边在不在同一组(所以使用并查集来进行对分组合并问题的实现)
代码及解析:
1 //先写好点的并查集结构 2 public static class UnionFinds { 3 public HashMap<Node,Node> fatherMap;//记录边的父亲(所在分组) 4 public HashMap<Node,Integer> rankMap;//记录边所在的层级 5 6 public UnionFinds(Graph g) { 7 for (Node node : g.nodeis) { 8 fatherMap.put(node, node);//一开始把自己做为祖先 9 rankMap.put(node, 1); 10 } 11 } 12 13 public Node find(Node e) { 14 if (e != fatherMap.get(e)) { 15 fatherMap.put(e, find(e)); 16 } 17 return fatherMap.get(e); 18 } 19 20 public boolean Union(Node a,Node b) { 21 Node rootA = find(a); 22 Node rootB = find(b); 23 if (rootA == rootB) { 24 return false; 25 } 26 if (rankMap.get(rootA) < rankMap.get(rootB)) { 27 fatherMap.put(a, rootB); 28 } 29 else { 30 fatherMap.put(b, rootA); 31 if (rankMap.get(rootA) == rankMap.get(rootB)) { 32 rankMap.put(rootA, rankMap.get(rootA) + 1); 33 } 34 } 35 return true; 36 } 37 38 public boolean isSame(Node a,Node b) { 39 return find(a) == find(b); 40 } 41 }
执行实现Kruskal算法:
1 public static class EdgeComparator implements Comparator<Edge> { 2 public int compare(Edge e1,Edge e2) { 3 return e1.weight - e2.weight; 4 } 5 } 6 7 public static Set<Edge> Kruskals(Graph g) { 8 UnionFinds unionFind = new UnionFinds(g); 9 PriorityQueue<Edge> pq = new PriorityQueue<>(new EdgeComparator()); 10 for (Edge edge : g.edges) { 11 pq.add(edge); 12 } 13 Set<Edge> set = new HashSet<>(); 14 while (pq.size() > 0) { 15 Edge e = pq.poll(); 16 if (!unionFind.isSame(e.from, e.to)) { 17 unionFind.Union(e.from, e.to); 18 set.add(e); 19 } 20 } 21 return set; 22 }
2.Prim算法:
* 1.从第一个点(把该点存入点集)出发,将所有与这个点相连的边都加入到选择边集中,从中找出最短的边
* 如果这条边的两端都在点集中,则继续往下找,直到找到两端有一端不在点集中时,将这条边引入答案边集,并
* 把边的两端都引入点集(实际只加了一端,另一端已经存在)
* 2.将新点引入后,如果点集中已有全部的点,则直接结束操作。否则,新点又会带来若干条新边,
* 将所有的新边引入到选择边集后,重新回到1操作
1 public static class EdgeComparator implements Comparator<Edge> { 2 public int compare(Edge e1,Edge e2) { 3 return e1.weight - e2.weight; 4 } 5 } 6 7 public static Set<Edge> Prims(Graph g) { 8 PriorityQueue<Edge> pq = new PriorityQueue<>(new EdgeComparator());//选择边集 9 HashSet<Node> nodes = new HashSet<>();//存入已被连通的点集 10 HashSet<Edge> results = new HashSet<>();//答案边集 11 12 for (Node node : g.nodes.values()) {//随机选一个点,做为操作的起始点 13 14 if (!nodes.contains(node)) {//如果这个点不在已被连通的点集中 15 nodes.add(node); 16 for (Edge edge : node.edges) {//先对优先队列初始化,把初始点的连通边都加到队列中 17 pq.add(edge); 18 } 19 while (pq.size() > 0) {//等优先队列所有的边都被清空后结束 20 Edge edge = pq.poll();//弹出来的边不一定符合条件 21 Node toNode = edge.to; 22 if (!nodes.contains(toNode)) {//一定保证to节点不在已被连通点集中,才加入这条边 23 results.add(edge);//这条边即所要的其中一条边,加入到答案 24 nodes.add(toNode);//加完这条边,该点就在连通点集中 25 } 26 for (Edge e : toNode.edges) {//把新加的点的相连边都加入到选择边集中去 27 pq.add(e); 28 } 29 } 30 } 31 } 32 return results; 33 }