▶ 书中第四章部分程序,包括在加上自己补充的代码,Kruskal 算法和 Boruvka 算法求最小生成树
● Kruskal 算法求最小生成树
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.Edge; 6 import edu.princeton.cs.algs4.EdgeWeightedGraph; 7 import edu.princeton.cs.algs4.Queue; 8 import edu.princeton.cs.algs4.MinPQ; 9 import edu.princeton.cs.algs4.UF; 10 11 public class class01 12 { 13 private double weight; 14 private Queue<Edge> mst = new Queue<Edge>(); 15 16 public class01(EdgeWeightedGraph G) 17 { 18 MinPQ<Edge> pq = new MinPQ<Edge>(); // 建立最小优先队列 19 for (Edge e : G.edges()) 20 pq.insert(e); 21 for (UF uf = new UF(G.V()); !pq.isEmpty() && mst.size() < G.V() - 1;) // 加入生成树的变得集合 22 { 23 Edge e = pq.delMin(); // 取权值最小的边 24 int v = e.either(); 25 int w = e.other(v); 26 if (!uf.connected(v, w)) // 顶点 v 和 w 没有都在树中,说明添加边 v-w 不会构成环 27 { 28 uf.union(v, w); // 添加边,更新生成树的权值 29 mst.enqueue(e); 30 weight += e.weight(); 31 } 32 } 33 } 34 35 public Iterable<Edge> edges() 36 { 37 return mst; 38 } 39 40 public double weight() 41 { 42 return weight; 43 } 44 45 public static void main(String[] args) 46 { 47 In in = new In(args[0]); 48 EdgeWeightedGraph G = new EdgeWeightedGraph(in); 49 class01 mst = new class01(G); 50 for (Edge e : mst.edges()) 51 StdOut.println(e); 52 StdOut.printf("%.5f ", mst.weight()); 53 } 54 }
● Boruvka 算法求最小生成树
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.Edge; 6 import edu.princeton.cs.algs4.EdgeWeightedGraph; 7 import edu.princeton.cs.algs4.Bag; 8 import edu.princeton.cs.algs4.UF; 9 10 public class class01 11 { 12 private double weight; 13 private Bag<Edge> mst = new Bag<Edge>(); 14 15 public class01(EdgeWeightedGraph G) 16 { 17 UF uf = new UF(G.V()); 18 for (int t = 1; t < G.V() && mst.size() < G.V() - 1; t = t + t) // 重复 v-1 次直到得到生成树 19 { 20 Edge[] closest = new Edge[G.V()]; // 最小生成树中连接着顶点 v 的边记作 closest[v] 21 for (Edge e : G.edges()) 22 { 23 int v = e.either(), w = e.other(v); 24 int i = uf.find(v), j = uf.find(w); 25 if (i == j) // 顶点 v 和 w 来自同一棵树,加入边 v-w 会导致环 26 continue; 27 if (closest[i] == null || less(e, closest[i])) // v 是新顶点,加入边 v-w 会使得 v 的距离比现在小 28 closest[i] = e; // 值标记新距离,还没有加入边 29 if (closest[j] == null || less(e, closest[j])) // w 是新顶点,加入边 v-w 会使得 w 的距离比现在小 30 closest[j] = e; 31 } 32 for (int i = 0; i < G.V(); i++) 33 { 34 Edge e = closest[i]; 35 if (e != null) // 存在连着顶点 v 的最小生成树的边 36 { 37 int v = e.either(), w = e.other(v); // 正式加入边 v-w 38 if (!uf.connected(v, w)) // 防止已经在生成书中的边被再次添加 39 { 40 mst.add(e); 41 weight += e.weight(); 42 uf.union(v, w); 43 } 44 } 45 } 46 } 47 } 48 49 public Iterable<Edge> edges() 50 { 51 return mst; 52 } 53 54 public double weight() 55 { 56 return weight; 57 } 58 59 private static boolean less(Edge e, Edge f) // 比较两条边的权值 60 { 61 return e.weight() < f.weight(); 62 } 63 64 public static void main(String[] args) 65 { 66 In in = new In(args[0]); 67 EdgeWeightedGraph G = new EdgeWeightedGraph(in); 68 class01 mst = new class01(G); 69 for (Edge e : mst.edges()) 70 StdOut.println(e); 71 StdOut.printf("%.5f ", mst.weight()); 72 } 73 }