- Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathDijkstra.java
145 lines (121 loc) · 6.64 KB
/
Dijkstra.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
packagecom.jwetherell.algorithms.graph;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importjava.util.PriorityQueue;
importjava.util.Queue;
importcom.jwetherell.algorithms.data_structures.Graph;
/**
* Dijkstra's shortest path. Only works on non-negative path weights. Returns a
* tuple of total cost of shortest path and the path.
* <p>
* Worst case: O(|E| + |V| log |V|)
* <p>
* @see <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra's Algorithm (Wikipedia)</a>
* <br>
* @author Justin Wetherell <phishman3579@gmail.com>
*/
publicclassDijkstra {
privateDijkstra() { }
publicstaticMap<Graph.Vertex<Integer>, Graph.CostPathPair<Integer>> getShortestPaths(Graph<Integer> graph, Graph.Vertex<Integer> start) {
finalMap<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>> paths = newHashMap<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>>();
finalMap<Graph.Vertex<Integer>, Graph.CostVertexPair<Integer>> costs = newHashMap<Graph.Vertex<Integer>, Graph.CostVertexPair<Integer>>();
getShortestPath(graph, start, null, paths, costs);
finalMap<Graph.Vertex<Integer>, Graph.CostPathPair<Integer>> map = newHashMap<Graph.Vertex<Integer>, Graph.CostPathPair<Integer>>();
for (Graph.CostVertexPair<Integer> pair : costs.values()) {
intcost = pair.getCost();
Graph.Vertex<Integer> vertex = pair.getVertex();
List<Graph.Edge<Integer>> path = paths.get(vertex);
map.put(vertex, newGraph.CostPathPair<Integer>(cost, path));
}
returnmap;
}
publicstaticGraph.CostPathPair<Integer> getShortestPath(Graph<Integer> graph, Graph.Vertex<Integer> start, Graph.Vertex<Integer> end) {
if (graph == null)
throw (newNullPointerException("Graph must be non-NULL."));
// Dijkstra's algorithm only works on positive cost graphs
finalbooleanhasNegativeEdge = checkForNegativeEdges(graph.getVertices());
if (hasNegativeEdge)
throw (newIllegalArgumentException("Negative cost Edges are not allowed."));
finalMap<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>> paths = newHashMap<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>>();
finalMap<Graph.Vertex<Integer>, Graph.CostVertexPair<Integer>> costs = newHashMap<Graph.Vertex<Integer>, Graph.CostVertexPair<Integer>>();
returngetShortestPath(graph, start, end, paths, costs);
}
privatestaticGraph.CostPathPair<Integer> getShortestPath(Graph<Integer> graph,
Graph.Vertex<Integer> start, Graph.Vertex<Integer> end,
Map<Graph.Vertex<Integer>, List<Graph.Edge<Integer>>> paths,
Map<Graph.Vertex<Integer>, Graph.CostVertexPair<Integer>> costs) {
if (graph == null)
throw (newNullPointerException("Graph must be non-NULL."));
if (start == null)
throw (newNullPointerException("start must be non-NULL."));
// Dijkstra's algorithm only works on positive cost graphs
booleanhasNegativeEdge = checkForNegativeEdges(graph.getVertices());
if (hasNegativeEdge)
throw (newIllegalArgumentException("Negative cost Edges are not allowed."));
for (Graph.Vertex<Integer> v : graph.getVertices())
paths.put(v, newArrayList<Graph.Edge<Integer>>());
for (Graph.Vertex<Integer> v : graph.getVertices()) {
if (v.equals(start))
costs.put(v, newGraph.CostVertexPair<Integer>(0, v));
else
costs.put(v, newGraph.CostVertexPair<Integer>(Integer.MAX_VALUE, v));
}
finalQueue<Graph.CostVertexPair<Integer>> unvisited = newPriorityQueue<Graph.CostVertexPair<Integer>>();
unvisited.add(costs.get(start));
while (!unvisited.isEmpty()) {
finalGraph.CostVertexPair<Integer> pair = unvisited.remove();
finalGraph.Vertex<Integer> vertex = pair.getVertex();
// Compute costs from current vertex to all reachable vertices which haven't been visited
for (Graph.Edge<Integer> e : vertex.getEdges()) {
finalGraph.CostVertexPair<Integer> toPair = costs.get(e.getToVertex()); // O(1)
finalGraph.CostVertexPair<Integer> lowestCostToThisVertex = costs.get(vertex); // O(1)
finalintcost = lowestCostToThisVertex.getCost() + e.getCost();
if (toPair.getCost() == Integer.MAX_VALUE) {
// Haven't seen this vertex yet
// Need to remove the pair and re-insert, so the priority queue keeps it's invariants
unvisited.remove(toPair); // O(n)
toPair.setCost(cost);
unvisited.add(toPair); // O(log n)
// Update the paths
List<Graph.Edge<Integer>> set = paths.get(e.getToVertex()); // O(log n)
set.addAll(paths.get(e.getFromVertex())); // O(log n)
set.add(e);
} elseif (cost < toPair.getCost()) {
// Found a shorter path to a reachable vertex
// Need to remove the pair and re-insert, so the priority queue keeps it's invariants
unvisited.remove(toPair); // O(n)
toPair.setCost(cost);
unvisited.add(toPair); // O(log n)
// Update the paths
List<Graph.Edge<Integer>> set = paths.get(e.getToVertex()); // O(log n)
set.clear();
set.addAll(paths.get(e.getFromVertex())); // O(log n)
set.add(e);
}
}
// Termination conditions
if (end != null && vertex.equals(end)) {
// We are looking for shortest path to a specific vertex, we found it.
break;
}
}
if (end != null) {
finalGraph.CostVertexPair<Integer> pair = costs.get(end);
finalList<Graph.Edge<Integer>> set = paths.get(end);
return (newGraph.CostPathPair<Integer>(pair.getCost(), set));
}
returnnull;
}
privatestaticbooleancheckForNegativeEdges(Collection<Graph.Vertex<Integer>> vertitices) {
for (Graph.Vertex<Integer> v : vertitices) {
for (Graph.Edge<Integer> e : v.getEdges()) {
if (e.getCost() < 0)
returntrue;
}
}
returnfalse;
}
}