最小生成树

最小生成树:
* 在整个图连通的情况下,保证所有边的权值之和最小,找出这个图

 

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     }

 

posted @ 2022-04-17 20:59  jue1e0  阅读(18)  评论(0)    收藏  举报