Dijkstra's algorithm: Difference between revisions

Line 1,193:
 
=={{header|Java}}==
Algorithm is derived from Wikipedia section 'Using a priority queue'.
Notes for this solution:
This implementation finds the single path from a source to all reachable vertices.
* The number of nodes is fixed to less than 50
Building the graph from a set of edges takes O(E log V) for each pass.
* At every iteration, the next minimum distance node found by linear traversal of all nodes, which is inefficient.
Vertices are stored in a PriorityQueue (effectively a balanced binary heap), giving O(E log V) performance for removal of the head.
<lang java>import java.io.*;
Decreasing the distance of a vertex is accomplished by removing it from the heap and later re-inserting it.
The former takes linear time, resulting in a potential bottleneck.
Use of a Fibonacci heap (which doesn't exist in the standard Java library) would alleviate this issue.
<lang java>
import java.io.*;
import java.util.*;
 
public class GraphDijkstra {
private static final intGraph.Edge[] MAXNODESGRAPH = 50;{
new Graph.Edge("a", "b", 7),
private static final int INFINITY = Integer.MAX_VALUE;
new Graph.Edge("a", "c", 9),
int n;
new Graph.Edge("a", "f", 14),
int[][] weight = new int[MAXNODES][MAXNODES];
new Graph.Edge("b", "c", 10),
int[] distance = new int[MAXNODES];
int[] precede = new int[MAXNODES];Graph.Edge("b", "d", 15),
new Graph.Edge("c", "d", 11),
 
new Graph.Edge("c", "f", 2),
/**
new Graph.Edge("d", "e", 6),
* Find the shortest path across the graph using Dijkstra's algorithm.
new Graph.Edge("e", "f", 9),
*/
};
void buildSpanningTree(int source, int destination) {
private static final String START = "a";
boolean[] visit = new boolean[MAXNODES];
private static final String END = "e";
 
for (int i=0 ; i<n ; i++) {
public static void main(String[] args) {
distance[i] = INFINITY;
precede[i] Graph g = INFINITYnew Graph(GRAPH);
g.dijkstra(START);
}
g.printPath(END);
distance[source] = 0;
//g.printAllPaths();
 
}
int current = source;
while (current != destination) {
int distcurr = distance[current];
int smalldist = INFINITY;
int k = -1;
visit[current] = true;
 
for (int i=0; i<n; i++) {
if (visit[i])
continue;
 
int newdist = distcurr + weight[current][i];
if (newdist < distance[i]) {
distance[i] = newdist;
precede[i] = current;
}
if (distance[i] < smalldist) {
smalldist = distance[i];
k = i;
}
}
current = k;
}
}
 
/**
* Get the shortest path across a tree that has had its path weights
* calculated.
*/
int[] getShortestPath(int source, int destination) {
int i = destination;
int finall = 0;
int[] path = new int[MAXNODES];
 
path[finall] = destination;
finall++;
while (precede[i] != source) {
i = precede[i];
path[finall] = i;
finall++;
}
path[finall] = source;
 
int[] result = new int[finall+1];
System.arraycopy(path, 0, result, 0, finall+1);
return result;
}
 
/**
* Print the result.
*/
void displayResult(int[] path) {
System.out.println("\nThe shortest path followed is : \n");
for (int i = path.length-1 ; i>0 ; i--)
System.out.println("\t\t( " + path[i] + " ->" + path[i-1] +
" ) with cost = " + weight[path[i]][path[i-1]]);
System.out.println("For the Total Cost = " +
distance[path[path.length-1]]);
}
 
/**
* Prompt for a number.
*/
int getNumber(String msg) {
int ne = 0;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
 
try {
System.out.print("\n" + msg + " : ");
ne = Integer.parseInt(in.readLine());
} catch (Exception e) {
System.out.println("I/O Error");
}
return ne;
}
 
/**
* Prompt for a tree, build and display a path across it.
*/
void SPA() {
n = getNumber("Enter the number of nodes (Less than " + MAXNODES +
") in the matrix");
 
System.out.print("\nEnter the cost matrix : \n\n");
for (int i=0 ; i<n ; i++)
for (int j=0 ; j<n ; j++)
weight[i][j] = getNumber("Cost " + (i+1) + "--" + (j+1));
 
int s = getNumber("Enter the source node");
int d = getNumber("Enter the destination node");
 
buildSpanningTree(s, d);
displayResult(getShortestPath(s, d));
}
}
 
public class DijkstraGraph {
private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges
public static void main(String args[]) {
Graph g = new Graph();
/** One edge of the graph (only used by Graph constructor) */
g.SPA();
public static class Edge {
}
public final String v1, v2;
}</lang>
public final int dist;
public Edge(String v1, String v2, int dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}
/** One vertex of the graph, complete with mappings to neighbouring vertices */
public static class Vertex implements Comparable<Vertex> {
public final String name;
public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
public Vertex previous = null;
public final Map<Vertex, Integer> neighbours = new HashMap<>();
public Vertex(String name) {
this.name = name;
}
private void printPath() {
if (this == this.previous) {
System.out.printf("%s", this.name);
} else if (this.previous == null) {
System.out.printf("%s(unreached)", this.name);
} else {
this.previous.printPath();
System.out.printf(" -> %s(%d)", this.name, this.dist);
}
}
public int compareTo(Vertex other) {
return Integer.compare(dist, other.dist);
}
}
/** Builds a graph from a set of edges */
public Graph(Edge[] edges) {
graph = new HashMap<>(edges.length);
//one pass to find all vertices
for (Edge e : edges) {
if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1));
if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2));
}
//another pass to set neighbouring vertices
for (Edge e : edges) {
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
//graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
}
}
/** Runs dijkstra using a specified source vertex */
public void dijkstra(String startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
PriorityQueue<Vertex> q = new PriorityQueue<>(graph.size());
// set-up vertices
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Integer.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
/** Implementation of dijkstra's algorithm using a priority queue. */
private void dijkstra(final PriorityQueue<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {
u = q.poll(); // vertex with shortest distance (first iteration will return source)
if (u.dist == Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable
//look at distances to each neighbour
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
v = a.getKey(); //the neighbour in this iteration
final int alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
}
}
}
/** Prints a path from the source to the specified vertex */
public void printPath(String endName) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
return;
}
graph.get(endName).printPath();
System.out.println();
}
/** Prints the path from the source to every vertex (output order is not guaranteed) */
public void printAllPaths() {
for (Vertex v : graph.values()) {
v.printPath();
System.out.println();
}
}
}</lang>{{out}}<pre>
a -> c(9) -> d(20) -> e(26)
</pre>
 
=={{header|Mathematica}}==
41

edits