package ch.akuhn.graph2; import static org.junit.Assert.assertEquals; import java.util.Arrays; import org.junit.Test; public class DijkstrasAlgorithm { private static final int INFINITY = Integer.MAX_VALUE; public int[][] apply(Node[] nodes) { int[][] dist = new int[nodes.length][]; for (int n = 0; n < nodes.length; n++) { dist[n] = dijkstra(nodes, n); } return dist; } public int[] dijkstra(Node[] nodes, int curr) { // 1) Assign to every node a tentative distance value: set it to zero // for our initial node and to infinity for all other nodes. // 2) Mark all nodes unvisited. Set the initial node as current. Create // a set of the unvisited nodes called the unvisited set consisting of // all the nodes except the initial node. // 3) For the current node, consider all of its unvisited neighbors and // calculate their tentative distances. For example, if the current node // A is marked with a tentative distance of 6, and the edge connecting // it with a neighbor B has length 2, then the distance to B (through A) // will be 6+2=8. If this distance is less than the previously recorded // tentative distance of B, then overwrite that distance. Even though a // neighbor has been examined, it is not marked as "visited" at this // time, and it remains in the unvisited set. // 4) When we are done considering all of the neighbors of the current // node, mark the current node as visited and remove it from the // unvisited set. A visited node will never be checked again; its // distance recorded now is final and minimal. // 5) If the destination node has been marked visited (when planning a // route between two specific nodes) or if the smallest tentative // distance among the nodes in the unvisited set is infinity (when // planning a complete traversal), then stop. The algorithm has // finished. // 6) Set the unvisited node marked with the smallest tentative distance // as the next "current node" and go back to step 3. int[] dist = new int[nodes.length]; Arrays.fill(dist, INFINITY); dist[curr] = 0; boolean[] done = new boolean[nodes.length]; while (true) { int a = findNext(dist, done); if (a == -1) break; for (int b = 0; b < nodes.length; b++) { if (done[b]) continue; int d = nodes[a].cost[b]; if (d == INFINITY) continue; d += dist[a]; if (d < dist[b]) dist[b] = d; } done[a] = true; } return dist; } private int findNext(int[] dist, boolean[] done) { int found = -1; int cost = INFINITY; for (int i = 0; i < dist.length; i++) { if (done[i]) continue; if (dist[i] < cost) { cost = dist[i]; found = i; } } return found; } public static class Examples { @Test public void shouldFindShortestPath() { String s = "6 7\n1 2 20\n1 3 5\n1 4 10\n2 3 8\n2 4 15\n3 4 2\n5 6 9"; Node[] nodes = Node.parse(s); int[][] dist = new DijkstrasAlgorithm().apply(nodes); assertEquals(6, dist.length); } } }