| 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 | } |