1111
1212import java .util .ArrayList ;
1313import java .util .Arrays ;
14- import java .util .Collections ;
15- import java .util .Comparator ;
14+ import java .util .LinkedList ;
1615import java .util .List ;
1716import java .util .PriorityQueue ;
1817
1918public class DijkstrasShortestPathAdjacencyList {
2019
21- // Small epsilon value to comparing double values.
22- private static final double EPS = 1e-6 ;
23-
24- // An edge class to represent a directed edge
25- // between two nodes with a certain cost.
20+ // Represents a directed edge between two nodes with a certain cost.
2621 public static class Edge {
2722 double cost ;
2823 int from , to ;
@@ -34,115 +29,100 @@ public Edge(int from, int to, double cost) {
3429 }
3530 }
3631
37- // Node class to track the nodes to visit while running Dijkstra's
38- public static class Node {
32+ // Represents a node-distance pair for the priority queue.
33+ public static class Node implements Comparable < Node > {
3934 int id ;
4035 double value ;
4136
4237 public Node (int id , double value ) {
4338 this .id = id ;
4439 this .value = value ;
4540 }
41+
42+ @ Override
43+ public int compareTo (Node other ) {
44+ return Double .compare (this .value , other .value );
45+ }
4646 }
4747
48- private int n ;
48+ private final int n ;
4949 private double [] dist ;
5050 private Integer [] prev ;
51- private List <List <Edge >> graph ;
52-
53- private Comparator <Node > comparator =
54- new Comparator <Node >() {
55- @ Override
56- public int compare (Node node1 , Node node2 ) {
57- if (Math .abs (node1 .value - node2 .value ) < EPS ) return 0 ;
58- return (node1 .value - node2 .value ) > 0 ? +1 : -1 ;
59- }
60- };
51+ private final List <List <Edge >> graph ;
6152
6253 /**
63- * Initialize the solver by providing the graph size and a starting node . Use the {@link #addEdge}
64- * method to actually add edges to the graph.
54+ * Initialize the solver by providing the graph size. Use the {@link #addEdge} method to add edges
55+ * to the graph.
6556 *
6657 * @param n - The number of nodes in the graph.
6758 */
6859 public DijkstrasShortestPathAdjacencyList (int n ) {
6960 this .n = n ;
70- createEmptyGraph ();
71- }
72-
73- public DijkstrasShortestPathAdjacencyList (int n , Comparator <Node > comparator ) {
74- this (n );
75- if (comparator == null ) throw new IllegalArgumentException ("Comparator cannot be null" );
76- this .comparator = comparator ;
61+ this .graph = new ArrayList <>(n );
62+ for (int i = 0 ; i < n ; i ++)
63+ graph .add (new ArrayList <>());
7764 }
7865
7966 /**
8067 * Adds a directed edge to the graph.
8168 *
8269 * @param from - The index of the node the directed edge starts at.
83- * @param to - The index of the node the directed edge end at.
70+ * @param to - The index of the node the directed edge ends at.
8471 * @param cost - The cost of the edge.
8572 */
8673 public void addEdge (int from , int to , int cost ) {
8774 graph .get (from ).add (new Edge (from , to , cost ));
8875 }
8976
90- // Use {@link #addEdge} method to add edges to the graph and use this method
91- // to retrieve the constructed graph.
9277 public List <List <Edge >> getGraph () {
9378 return graph ;
9479 }
9580
9681 /**
9782 * Reconstructs the shortest path (of nodes) from 'start' to 'end' inclusive.
9883 *
99- * @return An array of nodes indexes of the shortest path from 'start' to 'end'. If 'start' and
100- * 'end' are not connected then an empty array is returned.
84+ * @return An array of node indexes of the shortest path from 'start' to 'end'. If 'start' and
85+ * 'end' are not connected then an empty list is returned.
10186 */
10287 public List <Integer > reconstructPath (int start , int end ) {
103- if ( end < 0 || end >= n ) throw new IllegalArgumentException ( "Invalid node index" );
104- if ( start < 0 || start >= n ) throw new IllegalArgumentException ( "Invalid node index" );
105- double dist = dijkstra ( start , end );
106- List < Integer > path = new ArrayList <>() ;
107- if ( dist == Double . POSITIVE_INFINITY ) return path ;
108- for ( Integer at = end ; at != null ; at = prev [ at ]) path .add (at );
109- Collections . reverse ( path );
88+ dijkstra ( start , end );
89+ LinkedList < Integer > path = new LinkedList <>( );
90+ if ( dist [ end ] == Double . POSITIVE_INFINITY )
91+ return path ;
92+ for ( int at = end ; at != start ; at = prev [ at ])
93+ path .addFirst (at );
94+ path . addFirst ( start );
11095 return path ;
11196 }
11297
113- // Run Dijkstra's algorithm on a directed graph to find the shortest path
114- // from a starting node to an ending node. If there is no path between the
115- // starting node and the destination node the returned value is set to be
116- // Double.POSITIVE_INFINITY.
98+ /**
99+ * Runs Dijkstra's algorithm on a directed graph to find the shortest path from a starting node to
100+ * an ending node. If there is no path between the starting node and the destination node the
101+ * returned value is Double.POSITIVE_INFINITY.
102+ */
117103 public double dijkstra (int start , int end ) {
118- // Maintain an array of the minimum distance to each node
119104 dist = new double [n ];
120105 Arrays .fill (dist , Double .POSITIVE_INFINITY );
121106 dist [start ] = 0 ;
122107
123108 // Keep a priority queue of the next most promising node to visit.
124- PriorityQueue <Node > pq = new PriorityQueue <>(2 * n , comparator );
109+ PriorityQueue <Node > pq = new PriorityQueue <>();
125110 pq .offer (new Node (start , 0 ));
126111
127- // Array used to track which nodes have already been visited.
128112 boolean [] visited = new boolean [n ];
129113 prev = new Integer [n ];
130114
131115 while (!pq .isEmpty ()) {
132116 Node node = pq .poll ();
133117 visited [node .id ] = true ;
134118
135- // We already found a better path before we got to
136- // processing this node so we can ignore it.
137- if (dist [node .id ] < node .value ) continue ;
138-
139- List <Edge > edges = graph .get (node .id );
140- for (int i = 0 ; i < edges .size (); i ++) {
141- Edge edge = edges .get (i );
119+ // We already found a better path before we got to processing this node.
120+ if (dist [node .id ] < node .value )
121+ continue ;
142122
143- // You cannot get a shorter path by revisiting
144- // a node you have already visited before.
145- if ( visited [ edge . to ]) continue ;
123+ for ( Edge edge : graph . get ( node . id )) {
124+ if ( visited [ edge . to ])
125+ continue ;
146126
147127 // Relax edge by updating minimum cost if applicable.
148128 double newDist = dist [edge .from ] + edge .cost ;
@@ -152,18 +132,12 @@ public double dijkstra(int start, int end) {
152132 pq .offer (new Node (edge .to , dist [edge .to ]));
153133 }
154134 }
155- // Once we've visited all the nodes spanning from the end
156- // node we know we can return the minimum distance value to
157- // the end node because it cannot get any better after this point.
158- if (node .id == end ) return dist [end ];
135+
136+ // Once we've processed the end node we can return early because the
137+ // distance cannot improve after this point.
138+ if (node .id == end )
139+ return dist [end ];
159140 }
160- // End node is unreachable
161141 return Double .POSITIVE_INFINITY ;
162142 }
163-
164- // Construct an empty graph with n nodes including the source and sink nodes.
165- private void createEmptyGraph () {
166- graph = new ArrayList <>(n );
167- for (int i = 0 ; i < n ; i ++) graph .add (new ArrayList <>());
168- }
169143}
0 commit comments