Ticket #7295: use_djikstra_assignment.patch
| File use_djikstra_assignment.patch, 38.1 KB (added by , 14 years ago) |
|---|
-
src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java
1 1 package org.openstreetmap.josm.plugins.utilsplugin2.replacegeometry; 2 2 3 import edu.princeton.cs.algs4.AssignmentProblem; 3 4 import java.awt.geom.Area; 4 5 import java.awt.geom.Point2D; 5 6 import java.util.*; … … 263 264 geometryPool.add(node); 264 265 } 265 266 266 boolean useHungarian = Main.pref.getBoolean("utilsplugin2.replace-geometry.robustAssignment", false);267 boolean useHungarian = Main.pref.getBoolean("utilsplugin2.replace-geometry.robustAssignment", true); 267 268 268 269 // Find new nodes that are closest to the old ones, remove matching old ones from the pool 269 270 // Assign node moves with least overall distance moved … … 272 273 if (useHungarian) { // use robust, but slower assignment 273 274 int gLen = geometryPool.size(); 274 275 int nLen = nodePool.size(); 275 double cost[][] = new double[nLen][gLen]; 276 int N = Math.max(gLen, nLen); 277 double cost[][] = new double[N][N]; 278 for (int i = 0; i < N; i++) { 279 for (int j = 0; j < N; j++) { 280 cost[i][j] = Double.MAX_VALUE; 281 } 282 } 276 283 277 284 double maxDistance = Double.parseDouble(Main.pref.get("utilsplugin2.replace-geometry.max-distance", "1")); 278 285 for (int i = 0; i < nLen; i++) { … … 285 292 } 286 293 } 287 294 } 288 int[][] assignment = HungarianAlgorithm.hgAlgorithm(cost, "min"); 289 for (int i = 0; i < nLen; i++) { 290 int nIdx = assignment[i][0]; 291 int gIdx = assignment[i][1]; 295 AssignmentProblem assignment = new AssignmentProblem(cost); 296 // int[][] assignment = HungarianAlgorithm.hgAlgorithm(cost, "min"); 297 for (int i = 0; i < N; i++) { 298 // int nIdx = assignment[i][0]; 299 // int gIdx = assignment[i][1]; 300 int nIdx = i; 301 int gIdx = assignment.sol(i); 292 302 if (cost[nIdx][gIdx] != Double.MAX_VALUE) { 293 303 nodeAssoc.put(geometryPool.get(gIdx), nodePool.get(nIdx)); 294 304 } -
src/edu/princeton/cs/algs4/EdgeWeightedDigraph.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac EdgeWeightedDigraph.java 5 * Execution: java EdgeWeightedDigraph V E 6 * Dependencies: Bag.java DirectedEdge.java 7 * 8 * An edge-weighted digraph, implemented using adjacency lists. 9 * 10 *************************************************************************/ 11 12 /** 13 * The <tt>EdgeWeightedDigraph</tt> class represents an directed graph of vertices 14 * named 0 through V-1, where each edge has a real-valued weight. 15 * It supports the following operations: add an edge to the graph, 16 * iterate over all of edges leaving a vertex. 17 * Parallel edges and self-loops are permitted. 18 * <p> 19 * For additional documentation, see <a href="http://algs4.cs.princeton.edu/44sp">Section 4.4</a> of 20 * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne. 21 */ 22 23 24 25 public class EdgeWeightedDigraph { 26 private final int V; 27 private int E; 28 private Bag<DirectedEdge>[] adj; 29 30 /** 31 * Create an empty edge-weighted digraph with V vertices. 32 */ 33 public EdgeWeightedDigraph(int V) { 34 if (V < 0) throw new RuntimeException("Number of vertices must be nonnegative"); 35 this.V = V; 36 this.E = 0; 37 adj = (Bag<DirectedEdge>[]) new Bag[V]; 38 for (int v = 0; v < V; v++) 39 adj[v] = new Bag<DirectedEdge>(); 40 } 41 42 /** 43 * Create a edge-weighted digraph with V vertices and E edges. 44 */ 45 public EdgeWeightedDigraph(int V, int E) { 46 this(V); 47 if (E < 0) throw new RuntimeException("Number of edges must be nonnegative"); 48 for (int i = 0; i < E; i++) { 49 int v = (int) (Math.random() * V); 50 int w = (int) (Math.random() * V); 51 double weight = Math.round(100 * Math.random()) / 100.0; 52 DirectedEdge e = new DirectedEdge(v, w, weight); 53 addEdge(e); 54 } 55 } 56 57 /** 58 * Create an edge-weighted digraph from input stream. 59 */ 60 // public EdgeWeightedDigraph(In in) { 61 // this(in.readInt()); 62 // int E = in.readInt(); 63 // for (int i = 0; i < E; i++) { 64 // int v = in.readInt(); 65 // int w = in.readInt(); 66 // double weight = in.readDouble(); 67 // addEdge(new DirectedEdge(v, w, weight)); 68 // } 69 // } 70 71 /** 72 * Copy constructor. 73 */ 74 public EdgeWeightedDigraph(EdgeWeightedDigraph G) { 75 this(G.V()); 76 this.E = G.E(); 77 for (int v = 0; v < G.V(); v++) { 78 // reverse so that adjacency list is in same order as original 79 Stack<DirectedEdge> reverse = new Stack<DirectedEdge>(); 80 for (DirectedEdge e : G.adj[v]) { 81 reverse.push(e); 82 } 83 for (DirectedEdge e : reverse) { 84 adj[v].add(e); 85 } 86 } 87 } 88 89 /** 90 * Return the number of vertices in this digraph. 91 */ 92 public int V() { 93 return V; 94 } 95 96 /** 97 * Return the number of edges in this digraph. 98 */ 99 public int E() { 100 return E; 101 } 102 103 104 /** 105 * Add the edge e to this digraph. 106 */ 107 public void addEdge(DirectedEdge e) { 108 int v = e.from(); 109 adj[v].add(e); 110 E++; 111 } 112 113 114 /** 115 * Return the edges leaving vertex v as an Iterable. 116 * To iterate over the edges leaving vertex v, use foreach notation: 117 * <tt>for (DirectedEdge e : graph.adj(v))</tt>. 118 */ 119 public Iterable<DirectedEdge> adj(int v) { 120 return adj[v]; 121 } 122 123 /** 124 * Return all edges in this graph as an Iterable. 125 * To iterate over the edges, use foreach notation: 126 * <tt>for (DirectedEdge e : graph.edges())</tt>. 127 */ 128 public Iterable<DirectedEdge> edges() { 129 Bag<DirectedEdge> list = new Bag<DirectedEdge>(); 130 for (int v = 0; v < V; v++) { 131 for (DirectedEdge e : adj(v)) { 132 list.add(e); 133 } 134 } 135 return list; 136 } 137 138 /** 139 * Return number of edges leaving v. 140 */ 141 public int outdegree(int v) { 142 return adj[v].size(); 143 } 144 145 146 147 /** 148 * Return a string representation of this graph. 149 */ 150 public String toString() { 151 String NEWLINE = System.getProperty("line.separator"); 152 StringBuilder s = new StringBuilder(); 153 s.append(V + " " + E + NEWLINE); 154 for (int v = 0; v < V; v++) { 155 s.append(v + ": "); 156 for (DirectedEdge e : adj[v]) { 157 s.append(e + " "); 158 } 159 s.append(NEWLINE); 160 } 161 return s.toString(); 162 } 163 164 /** 165 * Test client. 166 */ 167 // public static void main(String[] args) { 168 // In in = new In(args[0]); 169 // EdgeWeightedDigraph G = new EdgeWeightedDigraph(in); 170 // StdOut.println(G); 171 // } 172 173 } -
src/edu/princeton/cs/algs4/Stack.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac Stack.java 5 * Execution: java Stack < input.txt 6 * 7 * A generic stack, implemented using a linked list. Each stack 8 * element is of type Item. 9 * 10 * % more tobe.txt 11 * to be or not to - be - - that - - - is 12 * 13 * % java Stack < tobe.txt 14 * to be not that or be (2 left on stack) 15 * 16 *************************************************************************/ 17 18 import java.util.Iterator; 19 import java.util.NoSuchElementException; 20 21 22 /** 23 * The <tt>Stack</tt> class represents a last-in-first-out (LIFO) stack of generic items. 24 * It supports the usual <em>push</em> and <em>pop</em> operations, along with methods 25 * for peeking at the top item, testing if the stack is empty, and iterating through 26 * the items in LIFO order. 27 * <p> 28 * All stack operations except iteration are constant time. 29 * <p> 30 * For additional documentation, see <a href="/algs4/13stacks">Section 1.3</a> of 31 * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne. 32 */ 33 public class Stack<Item> implements Iterable<Item> { 34 private int N; // size of the stack 35 private Node first; // top of stack 36 37 // helper linked list class 38 private class Node { 39 private Item item; 40 private Node next; 41 } 42 43 /** 44 * Create an empty stack. 45 */ 46 public Stack() { 47 first = null; 48 N = 0; 49 assert check(); 50 } 51 52 /** 53 * Is the stack empty? 54 */ 55 public boolean isEmpty() { 56 return first == null; 57 } 58 59 /** 60 * Return the number of items in the stack. 61 */ 62 public int size() { 63 return N; 64 } 65 66 /** 67 * Add the item to the stack. 68 */ 69 public void push(Item item) { 70 Node oldfirst = first; 71 first = new Node(); 72 first.item = item; 73 first.next = oldfirst; 74 N++; 75 assert check(); 76 } 77 78 /** 79 * Delete and return the item most recently added to the stack. 80 * Throw an exception if no such item exists because the stack is empty. 81 */ 82 public Item pop() { 83 if (isEmpty()) throw new RuntimeException("Stack underflow"); 84 Item item = first.item; // save item to return 85 first = first.next; // delete first node 86 N--; 87 assert check(); 88 return item; // return the saved item 89 } 90 91 92 /** 93 * Return the item most recently added to the stack. 94 * Throw an exception if no such item exists because the stack is empty. 95 */ 96 public Item peek() { 97 if (isEmpty()) throw new RuntimeException("Stack underflow"); 98 return first.item; 99 } 100 101 /** 102 * Return string representation. 103 */ 104 public String toString() { 105 StringBuilder s = new StringBuilder(); 106 for (Item item : this) 107 s.append(item + " "); 108 return s.toString(); 109 } 110 111 112 // check internal invariants 113 private boolean check() { 114 if (N == 0) { 115 if (first != null) return false; 116 } 117 else if (N == 1) { 118 if (first == null) return false; 119 if (first.next != null) return false; 120 } 121 else { 122 if (first.next == null) return false; 123 } 124 125 // check internal consistency of instance variable N 126 int numberOfNodes = 0; 127 for (Node x = first; x != null; x = x.next) { 128 numberOfNodes++; 129 } 130 if (numberOfNodes != N) return false; 131 132 return true; 133 } 134 135 136 /** 137 * Return an iterator to the stack that iterates through the items in LIFO order. 138 */ 139 public Iterator<Item> iterator() { return new ListIterator(); } 140 141 // an iterator, doesn't implement remove() since it's optional 142 private class ListIterator implements Iterator<Item> { 143 private Node current = first; 144 public boolean hasNext() { return current != null; } 145 public void remove() { throw new UnsupportedOperationException(); } 146 147 public Item next() { 148 if (!hasNext()) throw new NoSuchElementException(); 149 Item item = current.item; 150 current = current.next; 151 return item; 152 } 153 } 154 155 156 /** 157 * A test client. 158 */ 159 // public static void main(String[] args) { 160 // Stack<String> s = new Stack<String>(); 161 // while (!StdIn.isEmpty()) { 162 // String item = StdIn.readString(); 163 // if (!item.equals("-")) s.push(item); 164 // else if (!s.isEmpty()) StdOut.print(s.pop() + " "); 165 // } 166 // StdOut.println("(" + s.size() + " left on stack)"); 167 // } 168 } 169 -
src/edu/princeton/cs/algs4/DirectedEdge.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac DirectedEdge.java 5 * Execution: java DirectedEdge 6 * 7 * Immutable weighted directed edge. 8 * 9 *************************************************************************/ 10 11 /** 12 * The <tt>DirectedEdge</tt> class represents a weighted edge in an directed graph. 13 * <p> 14 * For additional documentation, see <a href="http://algs4.cs.princeton.edu/44sp">Section 4.4</a> of 15 * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne. 16 */ 17 18 public class DirectedEdge { 19 private final int v; 20 private final int w; 21 private final double weight; 22 23 /** 24 * Create a directed edge from v to w with given weight. 25 */ 26 public DirectedEdge(int v, int w, double weight) { 27 this.v = v; 28 this.w = w; 29 this.weight = weight; 30 } 31 32 /** 33 * Return the vertex where this edge begins. 34 */ 35 public int from() { 36 return v; 37 } 38 39 /** 40 * Return the vertex where this edge ends. 41 */ 42 public int to() { 43 return w; 44 } 45 46 /** 47 * Return the weight of this edge. 48 */ 49 public double weight() { return weight; } 50 51 /** 52 * Return a string representation of this edge. 53 */ 54 public String toString() { 55 return v + "->" + w + " " + String.format("%5.2f", weight); 56 } 57 58 /** 59 * Test client. 60 */ 61 // public static void main(String[] args) { 62 // DirectedEdge e = new DirectedEdge(12, 23, 3.14); 63 // StdOut.println(e); 64 // } 65 } -
src/edu/princeton/cs/algs4/Bag.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac Bag.java 5 * Execution: java Bag < input.txt 6 * 7 * A generic bag or multiset, implemented using a linked list. 8 * 9 *************************************************************************/ 10 11 import java.util.Iterator; 12 import java.util.NoSuchElementException; 13 14 /** 15 * The <tt>Bag</tt> class represents a bag (or multiset) of 16 * generic items. It supports insertion and iterating over the 17 * items in arbitrary order. 18 * <p> 19 * The <em>add</em>, <em>isEmpty</em>, and <em>size</em> operation 20 * take constant time. Iteration takes time proportional to the number of items. 21 * <p> 22 * For additional documentation, see <a href="http://algs4.cs.princeton.edu/13stacks">Section 1.3</a> of 23 * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne. 24 */ 25 public class Bag<Item> implements Iterable<Item> { 26 private int N; // number of elements in bag 27 private Node first; // beginning of bag 28 29 // helper linked list class 30 private class Node { 31 private Item item; 32 private Node next; 33 } 34 35 /** 36 * Create an empty stack. 37 */ 38 public Bag() { 39 first = null; 40 N = 0; 41 assert check(); 42 } 43 44 /** 45 * Is the BAG empty? 46 */ 47 public boolean isEmpty() { 48 return first == null; 49 } 50 51 /** 52 * Return the number of items in the bag. 53 */ 54 public int size() { 55 return N; 56 } 57 58 /** 59 * Add the item to the bag. 60 */ 61 public void add(Item item) { 62 Node oldfirst = first; 63 first = new Node(); 64 first.item = item; 65 first.next = oldfirst; 66 N++; 67 assert check(); 68 } 69 70 // check internal invariants 71 private boolean check() { 72 if (N == 0) { 73 if (first != null) return false; 74 } 75 else if (N == 1) { 76 if (first == null) return false; 77 if (first.next != null) return false; 78 } 79 else { 80 if (first.next == null) return false; 81 } 82 83 // check internal consistency of instance variable N 84 int numberOfNodes = 0; 85 for (Node x = first; x != null; x = x.next) { 86 numberOfNodes++; 87 } 88 if (numberOfNodes != N) return false; 89 90 return true; 91 } 92 93 94 /** 95 * Return an iterator that iterates over the items in the bag. 96 */ 97 public Iterator<Item> iterator() { 98 return new ListIterator(); 99 } 100 101 // an iterator, doesn't implement remove() since it's optional 102 private class ListIterator implements Iterator<Item> { 103 private Node current = first; 104 105 public boolean hasNext() { return current != null; } 106 public void remove() { throw new UnsupportedOperationException(); } 107 108 public Item next() { 109 if (!hasNext()) throw new NoSuchElementException(); 110 Item item = current.item; 111 current = current.next; 112 return item; 113 } 114 } 115 116 } -
src/edu/princeton/cs/algs4/AssignmentProblem.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac AssignmentProblem.java 5 * Execution: java AssignmentProblem N 6 * Dependencies: DijkstraSP.java DirectedEdge.java 7 * 8 * Solve an N-by-N assignment problem in N^3 log N time using the 9 * successive shortest path algorithm. 10 * 11 * Remark: could use dense version of Dijsktra's algorithm for 12 * improved theoretical efficiency of N^3, but it doesn't seem to 13 * help in practice. 14 * 15 * Assumes N-by-N cost matrix is nonnegative. 16 * 17 * 18 *********************************************************************/ 19 20 public class AssignmentProblem { 21 private static final int UNMATCHED = -1; 22 23 private int N; // number of rows and columns 24 private double[][] weight; // the N-by-N cost matrix 25 private double[] px; // px[i] = dual variable for row i 26 private double[] py; // py[j] = dual variable for col j 27 private int[] xy; // xy[i] = j means i-j is a match 28 private int[] yx; // yx[j] = i means i-j is a match 29 30 31 public AssignmentProblem(double[][] weight) { 32 N = weight.length; 33 this.weight = new double[N][N]; 34 for (int i = 0; i < N; i++) 35 for (int j = 0; j < N; j++) 36 this.weight[i][j] = weight[i][j]; 37 38 // dual variables 39 px = new double[N]; 40 py = new double[N]; 41 42 // initial matching is empty 43 xy = new int[N]; 44 yx = new int[N]; 45 for (int i = 0; i < N; i++) xy[i] = UNMATCHED; 46 for (int j = 0; j < N; j++) yx[j] = UNMATCHED; 47 48 // add N edges to matching 49 for (int k = 0; k < N; k++) { 50 assert isDualFeasible(); 51 assert isComplementarySlack(); 52 augment(); 53 } 54 assert check(); 55 } 56 57 // find shortest augmenting path and upate 58 private void augment() { 59 60 // build residual graph 61 EdgeWeightedDigraph G = new EdgeWeightedDigraph(2*N+2); 62 int s = 2*N, t = 2*N+1; 63 for (int i = 0; i < N; i++) { 64 if (xy[i] == UNMATCHED) G.addEdge(new DirectedEdge(s, i, 0.0)); 65 } 66 for (int j = 0; j < N; j++) { 67 if (yx[j] == UNMATCHED) G.addEdge(new DirectedEdge(N+j, t, py[j])); 68 } 69 for (int i = 0; i < N; i++) { 70 for (int j = 0; j < N; j++) { 71 if (xy[i] == j) G.addEdge(new DirectedEdge(N+j, i, 0.0)); 72 else G.addEdge(new DirectedEdge(i, N+j, reduced(i, j))); 73 } 74 } 75 76 // compute shortest path from s to every other vertex 77 DijkstraSP spt = new DijkstraSP(G, s); 78 79 // augment along alternating path 80 for (DirectedEdge e : spt.pathTo(t)) { 81 int i = e.from(), j = e.to() - N; 82 if (i < N) { 83 xy[i] = j; 84 yx[j] = i; 85 } 86 } 87 88 // update dual variables 89 for (int i = 0; i < N; i++) px[i] += spt.distTo(i); 90 for (int j = 0; j < N; j++) py[j] += spt.distTo(N+j); 91 } 92 93 // reduced cost of i-j 94 private double reduced(int i, int j) { 95 return weight[i][j] + px[i] - py[j]; 96 } 97 98 // total weight of min weight perfect matching 99 public double weight() { 100 double total = 0.0; 101 for (int i = 0; i < N; i++) { 102 if (xy[i] != UNMATCHED) 103 total += weight[i][xy[i]]; 104 } 105 return total; 106 } 107 108 public int sol(int i) { 109 return xy[i]; 110 } 111 112 // check that dual variables are feasible 113 private boolean isDualFeasible() { 114 // check that all edges have >= 0 reduced cost 115 for (int i = 0; i < N; i++) { 116 for (int j = 0; j < N; j++) { 117 if (reduced(i, j) < 0) { 118 // StdOut.println("Dual variables are not feasible"); 119 return false; 120 } 121 } 122 } 123 return true; 124 } 125 126 // check that primal and dual variables are complementary slack 127 private boolean isComplementarySlack() { 128 129 // check that all matched edges have 0-reduced cost 130 for (int i = 0; i < N; i++) { 131 if ((xy[i] != UNMATCHED) && (reduced(i, xy[i]) != 0)) { 132 // StdOut.println("Primal and dual variables are not complementary slack"); 133 return false; 134 } 135 } 136 return true; 137 } 138 139 // check that primal variables are a perfect matching 140 private boolean isPerfectMatching() { 141 142 // check that xy[] is a perfect matching 143 boolean[] perm = new boolean[N]; 144 for (int i = 0; i < N; i++) { 145 if (perm[xy[i]]) { 146 // StdOut.println("Not a perfect matching"); 147 return false; 148 } 149 perm[xy[i]] = true; 150 } 151 152 // check that xy[] and yx[] are inverses 153 for (int j = 0; j < N; j++) { 154 if (xy[yx[j]] != j) { 155 // StdOut.println("xy[] and yx[] are not inverses"); 156 return false; 157 } 158 } 159 for (int i = 0; i < N; i++) { 160 if (yx[xy[i]] != i) { 161 // StdOut.println("xy[] and yx[] are not inverses"); 162 return false; 163 } 164 } 165 166 return true; 167 } 168 169 170 // check optimality conditions 171 private boolean check() { 172 return isPerfectMatching() && isDualFeasible() && isComplementarySlack(); 173 } 174 175 // public static void main(String[] args) { 176 // In in = new In(args[0]); 177 // int N = in.readInt(); 178 // double[][] weight = new double[N][N]; 179 // for (int i = 0; i < N; i++) { 180 // for (int j = 0; j < N; j++) { 181 // weight[i][j] = in.readDouble(); 182 // } 183 // } 184 // 185 // AssignmentProblem assignment = new AssignmentProblem(weight); 186 // StdOut.println("weight = " + assignment.weight()); 187 // for (int i = 0; i < N; i++) 188 // StdOut.println(i + "-" + assignment.sol(i) + " " + weight[i][assignment.sol(i)]); 189 // } 190 191 } -
src/edu/princeton/cs/algs4/IndexMinPQ.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac IndexMinPQ.java 5 * Execution: java IndexMinPQ 6 * 7 * Indexed PQ implementation using a binary heap. 8 * 9 *********************************************************************/ 10 11 import java.util.Iterator; 12 import java.util.NoSuchElementException; 13 14 public class IndexMinPQ<Key extends Comparable<Key>> implements Iterable<Integer> { 15 private int N; // number of elements on PQ 16 private int[] pq; // binary heap using 1-based indexing 17 private int[] qp; // inverse of pq - qp[pq[i]] = pq[qp[i]] = i 18 private Key[] keys; // keys[i] = priority of i 19 20 public IndexMinPQ(int NMAX) { 21 keys = (Key[]) new Comparable[NMAX + 1]; // make this of length NMAX?? 22 pq = new int[NMAX + 1]; 23 qp = new int[NMAX + 1]; // make this of length NMAX?? 24 for (int i = 0; i <= NMAX; i++) qp[i] = -1; 25 } 26 27 // is the priority queue empty? 28 public boolean isEmpty() { return N == 0; } 29 30 // is k an index on the priority queue? 31 public boolean contains(int k) { 32 return qp[k] != -1; 33 } 34 35 // number of keys in the priority queue 36 public int size() { 37 return N; 38 } 39 40 // associate key with index k 41 public void insert(int k, Key key) { 42 if (contains(k)) throw new NoSuchElementException("item is already in pq"); 43 N++; 44 qp[k] = N; 45 pq[N] = k; 46 keys[k] = key; 47 swim(N); 48 } 49 50 // return the index associated with a minimal key 51 public int minIndex() { 52 if (N == 0) throw new NoSuchElementException("Priority queue underflow"); 53 return pq[1]; 54 } 55 56 // return a minimal key 57 public Key minKey() { 58 if (N == 0) throw new NoSuchElementException("Priority queue underflow"); 59 return keys[pq[1]]; 60 } 61 62 // delete a minimal key and returns its associated index 63 public int delMin() { 64 if (N == 0) throw new NoSuchElementException("Priority queue underflow"); 65 int min = pq[1]; 66 exch(1, N--); 67 sink(1); 68 qp[min] = -1; // delete 69 keys[pq[N+1]] = null; // to help with garbage collection 70 pq[N+1] = -1; // not needed 71 return min; 72 } 73 74 // return key associated with index k 75 public Key keyOf(int k) { 76 if (!contains(k)) throw new NoSuchElementException("item is not in pq"); 77 else return keys[k]; 78 } 79 80 // change the key associated with index k 81 public void change(int k, Key key) { 82 changeKey(k, key); 83 } 84 85 // change the key associated with index k 86 public void changeKey(int k, Key key) { 87 if (!contains(k)) throw new NoSuchElementException("item is not in pq"); 88 keys[k] = key; 89 swim(qp[k]); 90 sink(qp[k]); 91 } 92 93 // decrease the key associated with index k 94 public void decreaseKey(int k, Key key) { 95 if (!contains(k)) throw new NoSuchElementException("item is not in pq"); 96 if (keys[k].compareTo(key) <= 0) throw new RuntimeException("illegal decrease"); 97 keys[k] = key; 98 swim(qp[k]); 99 } 100 101 // increase the key associated with index k 102 public void increaseKey(int k, Key key) { 103 if (!contains(k)) throw new NoSuchElementException("item is not in pq"); 104 if (keys[k].compareTo(key) >= 0) throw new RuntimeException("illegal decrease"); 105 keys[k] = key; 106 sink(qp[k]); 107 } 108 109 // delete the key associated with index k 110 public void delete(int k) { 111 if (!contains(k)) throw new NoSuchElementException("item is not in pq"); 112 int index = qp[k]; 113 exch(index, N--); 114 swim(index); 115 sink(index); 116 keys[k] = null; 117 qp[k] = -1; 118 } 119 120 121 /************************************************************** 122 * General helper functions 123 **************************************************************/ 124 private boolean greater(int i, int j) { 125 return keys[pq[i]].compareTo(keys[pq[j]]) > 0; 126 } 127 128 private void exch(int i, int j) { 129 int swap = pq[i]; pq[i] = pq[j]; pq[j] = swap; 130 qp[pq[i]] = i; qp[pq[j]] = j; 131 } 132 133 134 /************************************************************** 135 * Heap helper functions 136 **************************************************************/ 137 private void swim(int k) { 138 while (k > 1 && greater(k/2, k)) { 139 exch(k, k/2); 140 k = k/2; 141 } 142 } 143 144 private void sink(int k) { 145 while (2*k <= N) { 146 int j = 2*k; 147 if (j < N && greater(j, j+1)) j++; 148 if (!greater(k, j)) break; 149 exch(k, j); 150 k = j; 151 } 152 } 153 154 155 /*********************************************************************** 156 * Iterators 157 **********************************************************************/ 158 159 /** 160 * Return an iterator that iterates over all of the elements on the 161 * priority queue in ascending order. 162 * <p> 163 * The iterator doesn't implement <tt>remove()</tt> since it's optional. 164 */ 165 public Iterator<Integer> iterator() { return new HeapIterator(); } 166 167 private class HeapIterator implements Iterator<Integer> { 168 // create a new pq 169 private IndexMinPQ<Key> copy; 170 171 // add all elements to copy of heap 172 // takes linear time since already in heap order so no keys move 173 public HeapIterator() { 174 copy = new IndexMinPQ<Key>(pq.length - 1); 175 for (int i = 1; i <= N; i++) 176 copy.insert(pq[i], keys[pq[i]]); 177 } 178 179 public boolean hasNext() { return !copy.isEmpty(); } 180 public void remove() { throw new UnsupportedOperationException(); } 181 182 public Integer next() { 183 if (!hasNext()) throw new NoSuchElementException(); 184 return copy.delMin(); 185 } 186 } 187 188 189 // public static void main(String[] args) { 190 // // insert a bunch of strings 191 // String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" }; 192 // 193 // IndexMinPQ<String> pq = new IndexMinPQ<String>(strings.length); 194 // for (int i = 0; i < strings.length; i++) { 195 // pq.insert(i, strings[i]); 196 // } 197 // 198 // // delete and print each key 199 // while (!pq.isEmpty()) { 200 // int i = pq.delMin(); 201 // StdOut.println(i + " " + strings[i]); 202 // } 203 // StdOut.println(); 204 // 205 // // reinsert the same strings 206 // for (int i = 0; i < strings.length; i++) { 207 // pq.insert(i, strings[i]); 208 // } 209 // 210 // // print each key using the iterator 211 // for (int i : pq) { 212 // StdOut.println(i + " " + strings[i]); 213 // } 214 // while (!pq.isEmpty()) { 215 // pq.delMin(); 216 // } 217 // 218 // } 219 } -
src/edu/princeton/cs/algs4/DijkstraSP.java
1 package edu.princeton.cs.algs4; 2 3 /************************************************************************* 4 * Compilation: javac DijkstraSP.java 5 * Execution: java DijkstraSP input.txt s 6 * Dependencies: EdgeWeightedDigraph.java IndexMinPQ.java Stack.java DirectedEdge.java 7 * Data files: http://algs4.cs.princeton.edu/44sp/tinyEWD.txt 8 * http://algs4.cs.princeton.edu/44sp/mediumEWD.txt 9 * http://algs4.cs.princeton.edu/44sp/largeEWD.txt 10 * 11 * Dijkstra's algorithm. Computes the shortest path tree. 12 * Assumes all weights are nonnegative. 13 * 14 * % java DijkstraSP tinyEWD.txt 0 15 * 0 to 0 (0.00) 16 * 0 to 1 (1.05) 0->4 0.38 4->5 0.35 5->1 0.32 17 * 0 to 2 (0.26) 0->2 0.26 18 * 0 to 3 (0.99) 0->2 0.26 2->7 0.34 7->3 0.39 19 * 0 to 4 (0.38) 0->4 0.38 20 * 0 to 5 (0.73) 0->4 0.38 4->5 0.35 21 * 0 to 6 (1.51) 0->2 0.26 2->7 0.34 7->3 0.39 3->6 0.52 22 * 0 to 7 (0.60) 0->2 0.26 2->7 0.34 23 * 24 * % java DijkstraSP mediumEWD.txt 0 25 * 0 to 0 (0.00) 26 * 0 to 1 (0.71) 0->44 0.06 44->93 0.07 ... 107->1 0.07 27 * 0 to 2 (0.65) 0->44 0.06 44->231 0.10 ... 42->2 0.11 28 * 0 to 3 (0.46) 0->97 0.08 97->248 0.09 ... 45->3 0.12 29 * 0 to 4 (0.42) 0->44 0.06 44->93 0.07 ... 77->4 0.11 30 * ... 31 * 32 *************************************************************************/ 33 34 public class DijkstraSP { 35 private double[] distTo; // distTo[v] = distance of shortest s->v path 36 private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path 37 private IndexMinPQ<Double> pq; // priority queue of vertices 38 39 public DijkstraSP(EdgeWeightedDigraph G, int s) { 40 distTo = new double[G.V()]; 41 edgeTo = new DirectedEdge[G.V()]; 42 for (int v = 0; v < G.V(); v++) 43 distTo[v] = Double.POSITIVE_INFINITY; 44 distTo[s] = 0.0; 45 46 // relax vertices in order of distance from s 47 pq = new IndexMinPQ<Double>(G.V()); 48 pq.insert(s, distTo[s]); 49 while (!pq.isEmpty()) { 50 int v = pq.delMin(); 51 for (DirectedEdge e : G.adj(v)) 52 relax(e); 53 } 54 55 // check optimality conditions 56 assert check(G, s); 57 } 58 59 // relax edge e and update pq if changed 60 private void relax(DirectedEdge e) { 61 int v = e.from(), w = e.to(); 62 if (distTo[w] > distTo[v] + e.weight()) { 63 distTo[w] = distTo[v] + e.weight(); 64 edgeTo[w] = e; 65 if (pq.contains(w)) pq.change(w, distTo[w]); 66 else pq.insert(w, distTo[w]); 67 } 68 } 69 70 // length of shortest path from s to v 71 public double distTo(int v) { 72 return distTo[v]; 73 } 74 75 // is there a path from s to v? 76 public boolean hasPathTo(int v) { 77 return distTo[v] < Double.POSITIVE_INFINITY; 78 } 79 80 // shortest path from s to v as an Iterable, null if no such path 81 public Iterable<DirectedEdge> pathTo(int v) { 82 if (!hasPathTo(v)) return null; 83 Stack<DirectedEdge> path = new Stack<DirectedEdge>(); 84 for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) { 85 path.push(e); 86 } 87 return path; 88 } 89 90 91 // check optimality conditions: 92 // (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight() 93 // (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight() 94 private boolean check(EdgeWeightedDigraph G, int s) { 95 96 // check that edge weights are nonnegative 97 for (DirectedEdge e : G.edges()) { 98 if (e.weight() < 0) { 99 System.err.println("negative edge weight detected"); 100 return false; 101 } 102 } 103 104 // check that distTo[v] and edgeTo[v] are consistent 105 if (distTo[s] != 0.0 || edgeTo[s] != null) { 106 System.err.println("distTo[s] and edgeTo[s] inconsistent"); 107 return false; 108 } 109 for (int v = 0; v < G.V(); v++) { 110 if (v == s) continue; 111 if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) { 112 System.err.println("distTo[] and edgeTo[] inconsistent"); 113 return false; 114 } 115 } 116 117 // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() 118 for (int v = 0; v < G.V(); v++) { 119 for (DirectedEdge e : G.adj(v)) { 120 int w = e.to(); 121 if (distTo[v] + e.weight() < distTo[w]) { 122 System.err.println("edge " + e + " not relaxed"); 123 return false; 124 } 125 } 126 } 127 128 // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() 129 for (int w = 0; w < G.V(); w++) { 130 if (edgeTo[w] == null) continue; 131 DirectedEdge e = edgeTo[w]; 132 int v = e.from(); 133 if (w != e.to()) return false; 134 if (distTo[v] + e.weight() != distTo[w]) { 135 System.err.println("edge " + e + " on shortest path not tight"); 136 return false; 137 } 138 } 139 return true; 140 } 141 142 143 // public static void main(String[] args) { 144 // In in = new In(args[0]); 145 // EdgeWeightedDigraph G = new EdgeWeightedDigraph(in); 146 // int s = Integer.parseInt(args[1]); 147 // 148 // // compute shortest paths 149 // DijkstraSP sp = new DijkstraSP(G, s); 150 // 151 // 152 // // print shortest path 153 // for (int t = 0; t < G.V(); t++) { 154 // if (sp.hasPathTo(t)) { 155 // StdOut.printf("%d to %d (%.2f) ", s, t, sp.distTo(t)); 156 // if (sp.hasPathTo(t)) { 157 // for (DirectedEdge e : sp.pathTo(t)) { 158 // StdOut.print(e + " "); 159 // } 160 // } 161 // StdOut.println(); 162 // } 163 // else { 164 // StdOut.printf("%d to %d no path\n", s, t); 165 // } 166 // } 167 // } 168 169 }
