Skip to content

Commit 60953b6

Browse files
committed
added dijkstra, mst
1 parent a8af67d commit 60953b6

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

CCSPiJ/src/chapter4/WeightedGraph.java

+155
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package chapter4;
22

33
import java.util.Arrays;
4+
import java.util.Collections;
5+
import java.util.HashMap;
6+
import java.util.LinkedList;
47
import java.util.List;
8+
import java.util.Map;
9+
import java.util.PriorityQueue;
10+
import java.util.function.IntConsumer;
511

612
public class WeightedGraph<V> extends Graph<V, WeightedEdge> {
713

@@ -38,6 +44,138 @@ public String toString() {
3844
return sb.toString();
3945
}
4046

47+
public static double totalWeight(List<WeightedEdge> path) {
48+
return path.stream().mapToDouble(we -> we.weight).sum();
49+
}
50+
51+
// Find the minimum-spanning tree of this graph using Jarnik's algorithm
52+
// *start* is the vertex index to start the search at
53+
public List<WeightedEdge> mst(int start) {
54+
LinkedList<WeightedEdge> result = new LinkedList<>(); // final mst
55+
PriorityQueue<WeightedEdge> pq = new PriorityQueue();
56+
boolean[] visited = new boolean[getVertexCount()]; // where we've been
57+
58+
// this is like a "visit" inner function
59+
IntConsumer visit = index -> {
60+
visited[index] = true; // mark as visited
61+
for (WeightedEdge edge : edgesOf(index)) {
62+
// add all edges coming from here to pq
63+
if (!visited[edge.v]) {
64+
pq.offer(edge);
65+
}
66+
}
67+
};
68+
69+
visit.accept(start); // the first vertex is where everything begins
70+
while (!pq.isEmpty()) { // keep going while there are edges to process
71+
WeightedEdge edge = pq.poll();
72+
if (visited[edge.v]) {
73+
continue; // don't ever revisit
74+
}
75+
// this is the current smallest, so add it to solution
76+
result.add(edge);
77+
visit.accept(edge.v); // visit where this connects
78+
}
79+
80+
return result;
81+
}
82+
83+
public void printWeightedPath(List<WeightedEdge> wp) {
84+
for (WeightedEdge edge : wp) {
85+
System.out.println(vertexAt(edge.u) + " " + edge.weight + "> " + vertexAt(edge.v));
86+
}
87+
System.out.println("Total Weight: " + totalWeight(wp));
88+
}
89+
90+
public static final class DijkstraNode implements Comparable<DijkstraNode> {
91+
public final int vertex;
92+
public final double distance;
93+
94+
public DijkstraNode(int vertex, double distance) {
95+
this.vertex = vertex;
96+
this.distance = distance;
97+
}
98+
99+
@Override
100+
public int compareTo(DijkstraNode other) {
101+
Double mine = distance;
102+
Double theirs = other.distance;
103+
return mine.compareTo(theirs);
104+
}
105+
}
106+
107+
public static final class DijkstraResult {
108+
public final double[] distances;
109+
public final Map<Integer, WeightedEdge> pathMap;
110+
111+
public DijkstraResult(double[] distances, Map<Integer, WeightedEdge> pathMap) {
112+
this.distances = distances;
113+
this.pathMap = pathMap;
114+
}
115+
}
116+
117+
public DijkstraResult dijkstra(V root) {
118+
int first = indexOf(root); // find starting index
119+
// distances are unknown at first
120+
double[] distances = new double[getVertexCount()];
121+
distances[first] = 0; // root's distance to root is 0
122+
boolean[] visited = new boolean[getVertexCount()]; // where we've been
123+
visited[first] = true;
124+
// how we got to each vertex
125+
HashMap<Integer, WeightedEdge> pathMap = new HashMap<>();
126+
PriorityQueue<DijkstraNode> pq = new PriorityQueue<>();
127+
pq.offer(new DijkstraNode(first, 0));
128+
129+
while (!pq.isEmpty()) {
130+
int u = pq.poll().vertex; // explore the next closest vertex
131+
double distU = distances[u]; // should already have seen it
132+
// look at every edge/vertex from the vertex in question
133+
for (WeightedEdge we : edgesOf(u)) {
134+
// the old distance to this vertex
135+
double distV = distances[we.v];
136+
double pathWeight = we.weight + distU;
137+
// new vertex or found shorter path?
138+
if (!visited[we.v] || (distV > pathWeight)) {
139+
visited[we.v] = true;
140+
// update the distance to this vertex
141+
distances[we.v] = pathWeight;
142+
// update the edge on the shortest path to this vertex
143+
pathMap.put(we.v, we);
144+
// explore it in the future
145+
pq.offer(new DijkstraNode(we.v, pathWeight));
146+
}
147+
}
148+
}
149+
150+
return new DijkstraResult(distances, pathMap);
151+
}
152+
153+
// Helper function to get easier access to dijkstra results
154+
public Map<V, Double> distanceArrayToDistanceMap(double[] distances) {
155+
HashMap<V, Double> distanceMap = new HashMap<>();
156+
for (int i = 0; i < distances.length; i++) {
157+
distanceMap.put(vertexAt(i), distances[i]);
158+
}
159+
return distanceMap;
160+
}
161+
162+
// Takes a map of edges to reach each node and return a list of
163+
// edges that goes from *start* to *end*
164+
public static List<WeightedEdge> pathMapToPath(int start, int end, Map<Integer, WeightedEdge> pathMap) {
165+
if (pathMap.size() == 0) {
166+
return List.of();
167+
}
168+
LinkedList<WeightedEdge> path = new LinkedList<>();
169+
WeightedEdge edge = pathMap.get(end);
170+
path.add(edge);
171+
while (edge.u != start) {
172+
edge = pathMap.get(edge.u);
173+
path.add(edge);
174+
}
175+
Collections.reverse(path);
176+
return path;
177+
}
178+
41179
// Test basic Graph construction
42180
public static void main(String[] args) {
43181
// Represents the 15 largest MSAs in the United States
@@ -73,6 +211,23 @@ public static void main(String[] args) {
73211
cityGraph2.addEdge("Philadelphia", "Washington", 123);
74212

75213
System.out.println(cityGraph2);
214+
215+
List<WeightedEdge> mst = cityGraph2.mst(0);
216+
cityGraph2.printWeightedPath(mst);
217+
218+
System.out.println(); // spacing
219+
220+
DijkstraResult dijkstraResult = cityGraph2.dijkstra("Los Angeles");
221+
Map<String, Double> nameDistance = cityGraph2.distanceArrayToDistanceMap(dijkstraResult.distances);
222+
System.out.println("Distances from Los Angeles:");
223+
nameDistance.forEach((name, distance) -> System.out.println(name + " : " + distance));
224+
225+
System.out.println(); // spacing
226+
227+
System.out.println("Shortest path from Los Angeles to Boston:");
228+
List<WeightedEdge> path = pathMapToPath(cityGraph2.indexOf("Los Angeles"), cityGraph2.indexOf("Boston"),
229+
dijkstraResult.pathMap);
230+
cityGraph2.printWeightedPath(path);
76231
}
77232

78233
}

0 commit comments

Comments
 (0)