▶ 书中第四章部分程序,包括在加上自己补充的代码,Dijkstra 算法求有向 / 无向图最短路径,以及所有顶点对之间的最短路径
● Dijkstra 算法求有向图最短路径
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.DirectedEdge; 6 import edu.princeton.cs.algs4.EdgeWeightedDigraph; 7 import edu.princeton.cs.algs4.Stack; 8 import edu.princeton.cs.algs4.IndexMinPQ; 9 10 public class class01 11 { 12 private double[] distTo; // 起点到各顶点的距离 13 private DirectedEdge[] edgeTo; // 由于引入顶点 v 使得图中新增加的边记作 edgeTo[v] 14 private IndexMinPQ<Double> pq; // 搜索队列 15 16 public class01(EdgeWeightedDigraph G, int s) 17 { 18 for (DirectedEdge e : G.edges()) // 确认所有变的权值为正 19 { 20 if (e.weight() < 0) 21 throw new IllegalArgumentException(" <Constructor> e.weight < 0. "); 22 } 23 distTo = new double[G.V()]; 24 edgeTo = new DirectedEdge[G.V()]; 25 for (int v = 0; v < G.V(); v++) 26 distTo[v] = Double.POSITIVE_INFINITY; 27 distTo[s] = 0.0; // 起点 28 pq = new IndexMinPQ<Double>(G.V()); 29 for (pq.insert(s, distTo[s]); !pq.isEmpty();) // 每次从搜索队列中取出一个顶点,松弛与之相连的所有边 30 { 31 int v = pq.delMin(); 32 for (DirectedEdge e : G.adj(v)) 33 relax(e); 34 } 35 } 36 37 private void relax(DirectedEdge e) 38 { 39 int v = e.from(), w = e.to(); 40 if (distTo[w] > distTo[v] + e.weight()) // 加入这条边会使起点到 w 的距离变短 41 { 42 distTo[w] = distTo[v] + e.weight(); // 加入该条边,更新 w 距离 43 edgeTo[w] = e; 44 if (pq.contains(w)) // 若 w 已经在搜索队列中 45 pq.decreaseKey(w, distTo[w]); // 更新 w 在搜索队列中的权值为当前起点到 w 的距离 46 else 47 pq.insert(w, distTo[w]); // 否则将顶点 w 加入搜索队列 48 } 49 } 50 51 public double distTo(int v) 52 { 53 return distTo[v]; 54 } 55 56 public boolean hasPathTo(int v) 57 { 58 return distTo[v] < Double.POSITIVE_INFINITY; 59 } 60 61 public Iterable<DirectedEdge> pathTo(int v) // 生成起点到 v 的最短路径 62 { 63 if (!hasPathTo(v)) 64 return null; 65 Stack<DirectedEdge> path = new Stack<DirectedEdge>(); 66 for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) // 从 v 开始不断寻找父顶点,依次压入栈中 67 path.push(e); 68 return path; 69 } 70 71 public static void main(String[] args) 72 { 73 In in = new In(args[0]); 74 int s = Integer.parseInt(args[1]); 75 EdgeWeightedDigraph G = new EdgeWeightedDigraph(in); 76 class01 sp = new class01(G, s); 77 for (int t = 0; t < G.V(); t++) 78 { 79 if (sp.hasPathTo(t)) 80 { 81 StdOut.printf("%d to %d (%.2f) ", s, t, sp.distTo(t)); 82 for (DirectedEdge e : sp.pathTo(t)) 83 StdOut.print(e + " "); 84 StdOut.println(); 85 } 86 else 87 StdOut.printf("%d to %d no path ", s, t); 88 } 89 } 90 }
● Dijkstra 算法求无向图最短路径
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.Stack; 8 import edu.princeton.cs.algs4.IndexMinPQ; 9 10 public class class01 11 { 12 private double[] distTo; 13 private Edge[] edgeTo; 14 private IndexMinPQ<Double> pq; 15 16 public class01(EdgeWeightedGraph G, int s) 17 { 18 for (Edge e : G.edges()) 19 { 20 if (e.weight() < 0) 21 throw new IllegalArgumentException(" <Constructor> e.weight < 0. "); 22 } 23 distTo = new double[G.V()]; 24 edgeTo = new Edge[G.V()]; 25 for (int v = 0; v < G.V(); v++) 26 distTo[v] = Double.POSITIVE_INFINITY; 27 distTo[s] = 0.0; 28 pq = new IndexMinPQ<Double>(G.V()); 29 for (pq.insert(s, distTo[s]); !pq.isEmpty();) 30 { 31 int v = pq.delMin(); 32 for (Edge e : G.adj(v)) 33 relax(e, v); 34 } 35 } 36 37 private void relax(Edge e, int v) // 无向图没有 from 和 to 分量,需要给出新边已经遍历了的那个顶点 38 { 39 int w = e.other(v); 40 if (distTo[w] > distTo[v] + e.weight()) 41 { 42 distTo[w] = distTo[v] + e.weight(); 43 edgeTo[w] = e; 44 if (pq.contains(w)) 45 pq.decreaseKey(w, distTo[w]); 46 else 47 pq.insert(w, distTo[w]); 48 } 49 } 50 51 public double distTo(int v) 52 { 53 return distTo[v]; 54 } 55 56 public boolean hasPathTo(int v) 57 { 58 return distTo[v] < Double.POSITIVE_INFINITY; 59 } 60 61 public Iterable<Edge> pathTo(int v) 62 { 63 if (!hasPathTo(v)) 64 return null; 65 Stack<Edge> path = new Stack<Edge>(); 66 int x = v; // 无向图需要变量记录父顶点,以便向回跳 67 for (Edge e = edgeTo[v]; e != null; e = edgeTo[x]) 68 { 69 path.push(e); 70 x = e.other(x); 71 } 72 return path; 73 } 74 75 public static void main(String[] args) 76 { 77 In in = new In(args[0]); 78 int s = Integer.parseInt(args[1]); 79 EdgeWeightedGraph G = new EdgeWeightedGraph(in); 80 class01 sp = new class01(G, s); 81 for (int t = 0; t < G.V(); t++) 82 { 83 if (sp.hasPathTo(t)) 84 { 85 StdOut.printf("%d to %d (%.2f) ", s, t, sp.distTo(t)); 86 for (Edge e : sp.pathTo(t)) 87 StdOut.print(e + " "); 88 StdOut.println(); 89 } 90 else 91 StdOut.printf("%d to %d no path ", s, t); 92 } 93 } 94 }
● Dijkstra 算法求所有顶点对之间的最短路径
1 package package01; 2 3 import edu.princeton.cs.algs4.In; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.DijkstraSP; 6 import edu.princeton.cs.algs4.DirectedEdge; 7 import edu.princeton.cs.algs4.EdgeWeightedDigraph; 8 9 public class class01 10 { 11 private DijkstraSP[] all; 12 13 public class01(EdgeWeightedDigraph G) 14 { 15 all = new DijkstraSP[G.V()]; 16 for (int v = 0; v < G.V(); v++) // 循环,每个点为起点都来一次 DijkstraSP 17 all[v] = new DijkstraSP(G, v); 18 } 19 20 public Iterable<DirectedEdge> path(int s, int t) 21 { 22 return all[s].pathTo(t); 23 } 24 25 public boolean hasPath(int s, int t) 26 { 27 return dist(s, t) < Double.POSITIVE_INFINITY; 28 } 29 30 public double dist(int s, int t) 31 { 32 return all[s].distTo(t); 33 } 34 35 public static void main(String[] args) 36 { 37 In in = new In(args[0]); 38 EdgeWeightedDigraph G = new EdgeWeightedDigraph(in); 39 class01 spt = new class01(G); 40 StdOut.printf(" "); // 输出没对定点之间的最小路径距离 41 for (int v = 0; v < G.V(); v++) 42 StdOut.printf("%6d ", v); 43 StdOut.println(); 44 for (int v = 0; v < G.V(); v++) 45 { 46 StdOut.printf("%3d: ", v); 47 for (int w = 0; w < G.V(); w++) 48 { 49 if (spt.hasPath(v, w)) StdOut.printf("%6.2f ", spt.dist(v, w)); 50 else StdOut.printf(" Inf "); 51 } 52 StdOut.println(); 53 } 54 StdOut.println(); 55 for (int v = 0; v < G.V(); v++) // 输出每对顶点之间最小路径 56 { 57 for (int w = 0; w < G.V(); w++) 58 { 59 if (spt.hasPath(v, w)) 60 { 61 StdOut.printf("%d to %d (%5.2f) ", v, w, spt.dist(v, w)); 62 for (DirectedEdge e : spt.path(v, w)) 63 StdOut.print(e + " "); 64 StdOut.println(); 65 } 66 else 67 StdOut.printf("%d to %d no path ", v, w); 68 } 69 } 70 } 71 }