/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: DijkstraAlgorithm.java 1681108 2015-05-22 13:26:12Z ssteiner $ */

package org.apache.xmlgraphics.util.dijkstra;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

This is an implementation of Dijkstra's algorithm to find the shortest path for a directed graph with non-negative edge weights.
See Also:
/** * This is an implementation of Dijkstra's algorithm to find the shortest path for a directed * graph with non-negative edge weights. * @see <a href="http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">WikiPedia on Dijkstra's * Algorithm</a> */
public class DijkstraAlgorithm {
Infinity value for distances.
/** Infinity value for distances. */
public static final int INFINITE = Integer.MAX_VALUE;
Compares penalties between two possible destinations.
/** Compares penalties between two possible destinations. */
private final Comparator penaltyComparator = new Comparator() { public int compare(Object left, Object right) { int leftPenalty = getLowestPenalty((Vertex)left); int rightPenalty = getLowestPenalty((Vertex)right); if (leftPenalty < rightPenalty) { return -1; } else if (leftPenalty == rightPenalty) { return ((Comparable)left).compareTo(right); } else { return 1; } } };
The directory of edges
/** The directory of edges */
private EdgeDirectory edgeDirectory;
The priority queue for all vertices under inspection, ordered by penalties/distances.
/** The priority queue for all vertices under inspection, ordered by penalties/distances. */
private TreeSet priorityQueue = new TreeSet(penaltyComparator); //Set<Vertex>
The set of vertices for which the lowest penalty has been found.
/** The set of vertices for which the lowest penalty has been found. */
private Set finishedVertices = new java.util.HashSet(); //Set<Vertex>
The currently known lowest penalties for all vertices.
/** The currently known lowest penalties for all vertices. */
private Map lowestPenalties = new java.util.HashMap(); //Map<Vertex,Integer>
Map of all predecessors in the spanning tree of best routes.
/** Map of all predecessors in the spanning tree of best routes. */
private Map predecessors = new java.util.HashMap(); //Map<Vertex,Vertex>
Main Constructor.
Params:
  • edgeDirectory – the edge directory this instance should work on
/** * Main Constructor. * @param edgeDirectory the edge directory this instance should work on */
public DijkstraAlgorithm(EdgeDirectory edgeDirectory) { this.edgeDirectory = edgeDirectory; }
Returns the penalty between two vertices.
Params:
  • start – the start vertex
  • end – the end vertex
Returns:the penalty between two vertices, or 0 if no single edge between the two vertices exists.
/** * Returns the penalty between two vertices. * @param start the start vertex * @param end the end vertex * @return the penalty between two vertices, or 0 if no single edge between the two vertices * exists. */
protected int getPenalty(Vertex start, Vertex end) { return this.edgeDirectory.getPenalty(start, end); }
Returns an iterator over all valid destinations for a given vertex.
Params:
  • origin – the origin from which to search for destinations
Returns:the iterator over all valid destinations for a given vertex
/** * Returns an iterator over all valid destinations for a given vertex. * @param origin the origin from which to search for destinations * @return the iterator over all valid destinations for a given vertex */
protected Iterator getDestinations(Vertex origin) { return this.edgeDirectory.getDestinations(origin); } private void reset() { finishedVertices.clear(); priorityQueue.clear(); lowestPenalties.clear(); predecessors.clear(); }
Run Dijkstra's shortest path algorithm. After this method is finished you can use getPredecessor(Vertex) to reconstruct the best/shortest path starting from the destination backwards.
Params:
  • start – the starting vertex
  • destination – the destination vertex.
/** * Run Dijkstra's shortest path algorithm. After this method is finished you can use * {@link #getPredecessor(Vertex)} to reconstruct the best/shortest path starting from the * destination backwards. * @param start the starting vertex * @param destination the destination vertex. */
public void execute(Vertex start, Vertex destination) { if (start == null || destination == null) { throw new NullPointerException("start and destination may not be null"); } reset(); setShortestDistance(start, 0); priorityQueue.add(start); // the current node Vertex u; // extract the vertex with the shortest distance while (priorityQueue.size() > 0) { u = (Vertex)priorityQueue.first(); priorityQueue.remove(u); if (destination.equals(u)) { //Destination reached break; } finishedVertices.add(u); relax(u); } }
Compute new lowest penalties for neighboring vertices. Update the lowest penalties and the predecessor map if a better solution is found.
Params:
  • u – the vertex to process
/** * Compute new lowest penalties for neighboring vertices. Update the lowest penalties and the * predecessor map if a better solution is found. * @param u the vertex to process */
private void relax(Vertex u) { Iterator iter = getDestinations(u); while (iter.hasNext()) { Vertex v = (Vertex)iter.next(); // skip node already settled if (isFinished(v)) { continue; } int shortDist = getLowestPenalty(u) + getPenalty(u, v); if (shortDist < getLowestPenalty(v)) { // assign new shortest distance and mark unsettled setShortestDistance(v, shortDist); // assign predecessor in shortest path setPredecessor(v, u); } } } private void setPredecessor(Vertex a, Vertex b) { predecessors.put(a, b); }
Indicates whether a shortest route to a vertex has been found.
Params:
  • v – the vertex
Returns:true if the shortest route to this vertex has been found.
/** * Indicates whether a shortest route to a vertex has been found. * @param v the vertex * @return true if the shortest route to this vertex has been found. */
private boolean isFinished(Vertex v) { return finishedVertices.contains(v); } private void setShortestDistance(Vertex vertex, int distance) { //Remove so it is inserted at the right position after the lowest penalty changes for this //vertex. priorityQueue.remove(vertex); //Update the lowest penalty. lowestPenalties.put(vertex, distance); //Insert the vertex again at the new position based on the lowest penalty priorityQueue.add(vertex); }
Returns the lowest penalty from the start point to a given vertex.
Params:
  • vertex – the vertex
Returns:the lowest penalty or INFINITE if there is no route to the destination.
/** * Returns the lowest penalty from the start point to a given vertex. * @param vertex the vertex * @return the lowest penalty or {@link DijkstraAlgorithm#INFINITE} if there is no route to * the destination. */
public int getLowestPenalty(Vertex vertex) { Integer d = ((Integer)lowestPenalties.get(vertex)); return (d == null) ? INFINITE : d; }
Returns the vertex's predecessor on the shortest path.
Params:
  • vertex – the vertex for which to find the predecessor
Returns:the vertex's predecessor on the shortest path, or null if there is no route to the destination.
/** * Returns the vertex's predecessor on the shortest path. * @param vertex the vertex for which to find the predecessor * @return the vertex's predecessor on the shortest path, or * <code>null</code> if there is no route to the destination. */
public Vertex getPredecessor(Vertex vertex) { return (Vertex)predecessors.get(vertex); } }