| 1 | // License: GPL v3 or later courtesy of author Kevin Wayne
|
|---|
| 2 | package edu.princeton.cs.algs4;
|
|---|
| 3 |
|
|---|
| 4 | /*************************************************************************
|
|---|
| 5 | * Compilation: javac DijkstraSP.java
|
|---|
| 6 | * Execution: java DijkstraSP input.txt s
|
|---|
| 7 | * Dependencies: EdgeWeightedDigraph.java IndexMinPQ.java Stack.java DirectedEdge.java
|
|---|
| 8 | * Data files: http://algs4.cs.princeton.edu/44sp/tinyEWD.txt
|
|---|
| 9 | * http://algs4.cs.princeton.edu/44sp/mediumEWD.txt
|
|---|
| 10 | * http://algs4.cs.princeton.edu/44sp/largeEWD.txt
|
|---|
| 11 | *
|
|---|
| 12 | * Dijkstra's algorithm. Computes the shortest path tree.
|
|---|
| 13 | * Assumes all weights are nonnegative.
|
|---|
| 14 | *
|
|---|
| 15 | * % java DijkstraSP tinyEWD.txt 0
|
|---|
| 16 | * 0 to 0 (0.00)
|
|---|
| 17 | * 0 to 1 (1.05) 0->4 0.38 4->5 0.35 5->1 0.32
|
|---|
| 18 | * 0 to 2 (0.26) 0->2 0.26
|
|---|
| 19 | * 0 to 3 (0.99) 0->2 0.26 2->7 0.34 7->3 0.39
|
|---|
| 20 | * 0 to 4 (0.38) 0->4 0.38
|
|---|
| 21 | * 0 to 5 (0.73) 0->4 0.38 4->5 0.35
|
|---|
| 22 | * 0 to 6 (1.51) 0->2 0.26 2->7 0.34 7->3 0.39 3->6 0.52
|
|---|
| 23 | * 0 to 7 (0.60) 0->2 0.26 2->7 0.34
|
|---|
| 24 | *
|
|---|
| 25 | * % java DijkstraSP mediumEWD.txt 0
|
|---|
| 26 | * 0 to 0 (0.00)
|
|---|
| 27 | * 0 to 1 (0.71) 0->44 0.06 44->93 0.07 ... 107->1 0.07
|
|---|
| 28 | * 0 to 2 (0.65) 0->44 0.06 44->231 0.10 ... 42->2 0.11
|
|---|
| 29 | * 0 to 3 (0.46) 0->97 0.08 97->248 0.09 ... 45->3 0.12
|
|---|
| 30 | * 0 to 4 (0.42) 0->44 0.06 44->93 0.07 ... 77->4 0.11
|
|---|
| 31 | * ...
|
|---|
| 32 | *
|
|---|
| 33 | *************************************************************************/
|
|---|
| 34 |
|
|---|
| 35 | public class DijkstraSP {
|
|---|
| 36 | private double[] distTo; // distTo[v] = distance of shortest s->v path
|
|---|
| 37 | private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path
|
|---|
| 38 | private IndexMinPQ<Double> pq; // priority queue of vertices
|
|---|
| 39 |
|
|---|
| 40 | public DijkstraSP(EdgeWeightedDigraph G, int s) {
|
|---|
| 41 | distTo = new double[G.V()];
|
|---|
| 42 | edgeTo = new DirectedEdge[G.V()];
|
|---|
| 43 | for (int v = 0; v < G.V(); v++)
|
|---|
| 44 | distTo[v] = Double.POSITIVE_INFINITY;
|
|---|
| 45 | distTo[s] = 0.0;
|
|---|
| 46 |
|
|---|
| 47 | // relax vertices in order of distance from s
|
|---|
| 48 | pq = new IndexMinPQ<>(G.V());
|
|---|
| 49 | pq.insert(s, distTo[s]);
|
|---|
| 50 | int count = 0;
|
|---|
| 51 | while (!pq.isEmpty()) {
|
|---|
| 52 | int v = pq.delMin();
|
|---|
| 53 | for (DirectedEdge e : G.adj(v))
|
|---|
| 54 | relax(e);
|
|---|
| 55 | count++;
|
|---|
| 56 | if (count > G.V())
|
|---|
| 57 | throw new RuntimeException("Exceeded limit");
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | // check optimality conditions
|
|---|
| 61 | assert check(G, s);
|
|---|
| 62 | }
|
|---|
| 63 |
|
|---|
| 64 | // relax edge e and update pq if changed
|
|---|
| 65 | private void relax(DirectedEdge e) {
|
|---|
| 66 | int v = e.from(), w = e.to();
|
|---|
| 67 | if (distTo[w] > distTo[v] + e.weight()) {
|
|---|
| 68 | distTo[w] = distTo[v] + e.weight();
|
|---|
| 69 | edgeTo[w] = e;
|
|---|
| 70 | if (pq.contains(w)) pq.change(w, distTo[w]);
|
|---|
| 71 | else pq.insert(w, distTo[w]);
|
|---|
| 72 | }
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | // length of shortest path from s to v
|
|---|
| 76 | public double distTo(int v) {
|
|---|
| 77 | return distTo[v];
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 | // is there a path from s to v?
|
|---|
| 81 | public boolean hasPathTo(int v) {
|
|---|
| 82 | return distTo[v] < Double.POSITIVE_INFINITY;
|
|---|
| 83 | }
|
|---|
| 84 |
|
|---|
| 85 | // shortest path from s to v as an Iterable, null if no such path
|
|---|
| 86 | public Iterable<DirectedEdge> pathTo(int v) {
|
|---|
| 87 | if (!hasPathTo(v)) return null;
|
|---|
| 88 | Stack<DirectedEdge> path = new Stack<>();
|
|---|
| 89 | for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) {
|
|---|
| 90 | path.push(e);
|
|---|
| 91 | }
|
|---|
| 92 | return path;
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 | // check optimality conditions:
|
|---|
| 97 | // (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight()
|
|---|
| 98 | // (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight()
|
|---|
| 99 | private boolean check(EdgeWeightedDigraph G, int s) {
|
|---|
| 100 |
|
|---|
| 101 | // check that edge weights are nonnegative
|
|---|
| 102 | for (DirectedEdge e : G.edges()) {
|
|---|
| 103 | if (e.weight() < 0) {
|
|---|
| 104 | System.err.println("negative edge weight detected");
|
|---|
| 105 | return false;
|
|---|
| 106 | }
|
|---|
| 107 | }
|
|---|
| 108 |
|
|---|
| 109 | // check that distTo[v] and edgeTo[v] are consistent
|
|---|
| 110 | if (distTo[s] != 0.0 || edgeTo[s] != null) {
|
|---|
| 111 | System.err.println("distTo[s] and edgeTo[s] inconsistent");
|
|---|
| 112 | return false;
|
|---|
| 113 | }
|
|---|
| 114 | for (int v = 0; v < G.V(); v++) {
|
|---|
| 115 | if (v == s) continue;
|
|---|
| 116 | if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) {
|
|---|
| 117 | System.err.println("distTo[] and edgeTo[] inconsistent");
|
|---|
| 118 | return false;
|
|---|
| 119 | }
|
|---|
| 120 | }
|
|---|
| 121 |
|
|---|
| 122 | // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight()
|
|---|
| 123 | for (int v = 0; v < G.V(); v++) {
|
|---|
| 124 | for (DirectedEdge e : G.adj(v)) {
|
|---|
| 125 | int w = e.to();
|
|---|
| 126 | if (distTo[v] + e.weight() < distTo[w]) {
|
|---|
| 127 | System.err.println("edge " + e + " not relaxed");
|
|---|
| 128 | return false;
|
|---|
| 129 | }
|
|---|
| 130 | }
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
|
|---|
| 134 | for (int w = 0; w < G.V(); w++) {
|
|---|
| 135 | if (edgeTo[w] == null) continue;
|
|---|
| 136 | DirectedEdge e = edgeTo[w];
|
|---|
| 137 | int v = e.from();
|
|---|
| 138 | if (w != e.to()) return false;
|
|---|
| 139 | if (distTo[v] + e.weight() != distTo[w]) {
|
|---|
| 140 | System.err.println("edge " + e + " on shortest path not tight");
|
|---|
| 141 | return false;
|
|---|
| 142 | }
|
|---|
| 143 | }
|
|---|
| 144 | return true;
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 | // public static void main(String[] args) {
|
|---|
| 149 | // In in = new In(args[0]);
|
|---|
| 150 | // EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
|
|---|
| 151 | // int s = Integer.parseInt(args[1]);
|
|---|
| 152 | //
|
|---|
| 153 | // // compute shortest paths
|
|---|
| 154 | // DijkstraSP sp = new DijkstraSP(G, s);
|
|---|
| 155 | //
|
|---|
| 156 | //
|
|---|
| 157 | // // print shortest path
|
|---|
| 158 | // for (int t = 0; t < G.V(); t++) {
|
|---|
| 159 | // if (sp.hasPathTo(t)) {
|
|---|
| 160 | // StdOut.printf("%d to %d (%.2f) ", s, t, sp.distTo(t));
|
|---|
| 161 | // if (sp.hasPathTo(t)) {
|
|---|
| 162 | // for (DirectedEdge e : sp.pathTo(t)) {
|
|---|
| 163 | // StdOut.print(e + " ");
|
|---|
| 164 | // }
|
|---|
| 165 | // }
|
|---|
| 166 | // StdOut.println();
|
|---|
| 167 | // }
|
|---|
| 168 | // else {
|
|---|
| 169 | // StdOut.printf("%d to %d no path\n", s, t);
|
|---|
| 170 | // }
|
|---|
| 171 | // }
|
|---|
| 172 | // }
|
|---|
| 173 |
|
|---|
| 174 | }
|
|---|