1 | /* |
2 | * $Id: DijkstraShortestPathFinder.java 5865 2005-10-25 21:02:06Z dfs $ |
3 | * |
4 | * Copyright 2004 Daniel F. Savarese |
5 | * Copyright 2005 Savarese Software Research |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. |
9 | * You may obtain a copy of the License at |
10 | * |
11 | * https://www.savarese.com/software/ApacheLicense-2.0 |
12 | * |
13 | * Unless required by applicable law or agreed to in writing, software |
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * See the License for the specific language governing permissions and |
17 | * limitations under the License. |
18 | */ |
19 | |
20 | package com.savarese.algorithms.graph; |
21 | |
22 | import java.util.*; |
23 | |
24 | /** |
25 | * The DijkstraShortestPathFinder class implements Dijkstra's |
26 | * algorithm, which solves the single source shortest paths problem. |
27 | * It finds all the shortest paths between a source vertex and every |
28 | * other vertex in a graph. |
29 | * |
30 | * @author <a href="https://www.savarese.com/">Daniel F. Savarese</a> |
31 | */ |
32 | |
33 | public class DijkstraShortestPathFinder<V, E extends Edge<V, Integer>> |
34 | implements SingleSourcePathFinder<V, Integer, E> |
35 | { |
36 | |
37 | public static final int INFINITY = Integer.MAX_VALUE; |
38 | |
39 | class PathData { |
40 | int _distance; |
41 | V _predecessor; |
42 | |
43 | PathData() { |
44 | this(INFINITY, null); |
45 | } |
46 | |
47 | PathData(int d, V p) { |
48 | _distance = d; |
49 | _predecessor = p; |
50 | } |
51 | } |
52 | |
53 | |
54 | class VertexComparator implements Comparator<V> { |
55 | public int compare(V o1, V o2) { |
56 | PathData p1 = __paths.get(o1); |
57 | PathData p2 = __paths.get(o2); |
58 | |
59 | if(p1._distance > p2._distance) |
60 | return 1; |
61 | else if(p1._distance == p2._distance) { |
62 | if(o1.equals(o2)) |
63 | return 0; |
64 | else |
65 | return (o1.hashCode() > o2.hashCode() ? 1 : -1); |
66 | } else |
67 | return -1; |
68 | } |
69 | } |
70 | |
71 | |
72 | class Solution implements SingleSourcePath<V, Integer> { |
73 | private HashMap<V, PathData> __paths; |
74 | private V __source; |
75 | |
76 | Solution(V source, HashMap<V, PathData> paths) { |
77 | __paths = paths; |
78 | __source = source; |
79 | } |
80 | |
81 | public V getSource() { |
82 | return __source; |
83 | } |
84 | |
85 | public Integer getDistance(V destination) { |
86 | PathData pd = __paths.get(destination); |
87 | |
88 | if(pd == null || pd._distance == INFINITY) |
89 | return null; |
90 | |
91 | return pd._distance; |
92 | } |
93 | |
94 | public void getPath(V destination, List<V> path) { |
95 | int size = path.size(); |
96 | |
97 | while(!__source.equals(destination)) { |
98 | PathData pd = __paths.get(destination); |
99 | |
100 | if(pd == null || destination == null) { |
101 | if(size == 0) |
102 | path.clear(); |
103 | else |
104 | for(int i = path.size() - 1; i >= size; --i) |
105 | path.remove(i); |
106 | return; |
107 | } |
108 | |
109 | path.add(size, destination); |
110 | destination = pd._predecessor; |
111 | } |
112 | |
113 | path.add(size, __source); |
114 | } |
115 | } |
116 | |
117 | |
118 | private HashMap<V, PathData> __paths; |
119 | private TreeSet<V> __queue; |
120 | |
121 | |
122 | public DijkstraShortestPathFinder() { |
123 | __paths = null; |
124 | __queue = new TreeSet<V>(new VertexComparator()); |
125 | } |
126 | |
127 | |
128 | private void __initPath(Graph<V, E> graph, V source) { |
129 | __paths = new HashMap<V, PathData>(); |
130 | |
131 | Iterator<V> vertices = graph.vertexSet().iterator(); |
132 | |
133 | while(vertices.hasNext()) { |
134 | V v = vertices.next(); |
135 | __paths.put(v, new PathData()); |
136 | __queue.add(v); |
137 | } |
138 | |
139 | PathData data = __paths.get(source); |
140 | __queue.remove(source); |
141 | data._distance = 0; |
142 | } |
143 | |
144 | |
145 | private void __relax(E e) { |
146 | V src = e.getSource(); |
147 | V dest = e.getDestination(); |
148 | |
149 | PathData destData = __paths.get(dest); |
150 | PathData srcData = __paths.get(src); |
151 | |
152 | int distance = srcData._distance + e.getWeight(); |
153 | |
154 | // distance >= 0 guards against overflow. |
155 | if(destData._distance > distance && distance >= 0) { |
156 | boolean add = __queue.remove(dest); |
157 | |
158 | destData._distance = distance; |
159 | destData._predecessor = src; |
160 | |
161 | // reorder queue |
162 | if(add) |
163 | __queue.add(dest); |
164 | } |
165 | } |
166 | |
167 | |
168 | /** |
169 | * Finds all the shortest paths in the given graph between the given |
170 | * source vertex and all other vertices in the graph. |
171 | * |
172 | * @param graph The graph to be searched. |
173 | * @param source The source vertex from which all paths will emanate. |
174 | * @return The paths found. |
175 | */ |
176 | public SingleSourcePath<V, Integer> |
177 | findPath(Graph<V, E> graph, V source) |
178 | { |
179 | __initPath(graph, source); |
180 | |
181 | V vertex = source; |
182 | |
183 | while(__queue.size() > 0) { |
184 | Iterator<E> edges = graph.edgeSet(vertex).iterator(); |
185 | |
186 | while(edges.hasNext()) |
187 | __relax(edges.next()); |
188 | |
189 | vertex = __queue.first(); |
190 | __queue.remove(vertex); |
191 | } |
192 | |
193 | __queue.clear(); |
194 | |
195 | Solution result = new Solution(source, __paths); |
196 | __paths = null; |
197 | |
198 | return result; |
199 | } |
200 | |
201 | } |