Patch from Dave to genericize ShortestPath.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@2574 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -27,54 +27,50 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements Dijkstra's algorithm for finding the shortest path between
|
* Implements Dijkstra's algorithm for finding the shortest path between two nodes in a weighted
|
||||||
* two nodes in a weighted graph. The code assumes that the caller
|
* graph. The code assumes that the caller represents their nodes and edges as objects which can
|
||||||
* represents their nodes and edges as objects which can be compared and
|
* be compared and hashed (via {@link Object#equals} and {@link Object#hashCode}) other necessary
|
||||||
* hashed (via {@link Object#equals} and {@link Object#hashCode}) other
|
* information is obtained through a special interface {@link Graph} implemented by the caller to
|
||||||
* necessary information is obtained through a special interface {@link
|
* enumerate edges and compute weights.
|
||||||
* Graph} implemented by the caller to enumerate edges and compute
|
|
||||||
* weights.
|
|
||||||
*/
|
*/
|
||||||
public class ShortestPath
|
public class ShortestPath
|
||||||
{
|
{
|
||||||
/** A caller must implement this interface to provide the information
|
/** A caller must implement this interface to provide the information needed to define the
|
||||||
* needed to define the graph and compute the shortest path. */
|
* graph and compute the shortest path.
|
||||||
public interface Graph
|
*/
|
||||||
|
public interface Graph<T, V>
|
||||||
{
|
{
|
||||||
/** Enumerates all nodes in the graph. */
|
/** Enumerates all nodes in the graph. */
|
||||||
public Iterator<Object> enumerateNodes ();
|
public Iterator<T> enumerateNodes ();
|
||||||
|
|
||||||
/** Returns the list of the edges for the specified node. */
|
/** Returns the list of the edges for the specified node. */
|
||||||
public List<Object> getEdges (Object node);
|
public List<V> getEdges (T node);
|
||||||
|
|
||||||
/** Returns the weight associated with the supplied edge in the
|
/** Returns the weight associated with the supplied edge in the direction established by
|
||||||
* direction established by the supplied starting node. */
|
* the supplied starting node. */
|
||||||
public int computeWeight (Object edge, Object start);
|
public int computeWeight (V edge, T start);
|
||||||
|
|
||||||
/** Returns the node opposite the supplied node on the supplied edge. */
|
/** Returns the node opposite the supplied node on the supplied edge. */
|
||||||
public Object getOpposite (Object edge, Object node);
|
public T getOpposite (V edge, T node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the shortest path between the specified starting and
|
* Computes the shortest path between the specified starting and ending nodes using Dijkstra's
|
||||||
* ending nodes using Dijkstra's algorithm. This implementation
|
* algorithm. This implementation assumes that the graph is properly formed and may behave
|
||||||
* assumes that the graph is properly formed and may behave strangely
|
* strangely or throw an exception if provided with an invalid graph.
|
||||||
* or throw an exception if provided with an invalid graph.
|
|
||||||
*
|
*
|
||||||
* @return a list of the edges that must be followed to traverse from the
|
* @return a list of the edges that must be followed to traverse from the starting node to the
|
||||||
* starting node to the ending node. This list may be empty if the graph is
|
* ending node. This list may be empty if the graph is improperly formed.
|
||||||
* improperly formed.
|
|
||||||
*/
|
*/
|
||||||
public static List<Object> compute (Graph graph, Object start, Object end)
|
public static <T, V> List<V> compute (Graph<T, V> graph, T start, T end)
|
||||||
{
|
{
|
||||||
HashMap<Object,NodeInfo> nodes = new HashMap<Object,NodeInfo>();
|
HashMap<T, NodeInfo<T, V>> nodes = new HashMap<T, NodeInfo<T, V>>();
|
||||||
HashSet<Object> relaxed = new HashSet<Object>();
|
HashSet<T> relaxed = new HashSet<T>();
|
||||||
ComparableArrayList<NodeInfo> uptight =
|
ComparableArrayList<NodeInfo<T, V>> uptight = new ComparableArrayList<NodeInfo<T, V>>();
|
||||||
new ComparableArrayList<NodeInfo>();
|
|
||||||
|
|
||||||
// initialize our searching info
|
// initialize our searching info
|
||||||
for (Iterator<Object> iter = graph.enumerateNodes(); iter.hasNext(); ) {
|
for (Iterator<T> iter = graph.enumerateNodes(); iter.hasNext(); ) {
|
||||||
NodeInfo info = new NodeInfo();
|
NodeInfo<T, V> info = new NodeInfo<T, V>();
|
||||||
info.node = iter.next();
|
info.node = iter.next();
|
||||||
if (info.node == start) {
|
if (info.node == start) {
|
||||||
info.weightTo = 0;
|
info.weightTo = 0;
|
||||||
@@ -87,21 +83,20 @@ public class ShortestPath
|
|||||||
// now execute the main part of the search
|
// now execute the main part of the search
|
||||||
while (uptight.size() > 0) {
|
while (uptight.size() > 0) {
|
||||||
// remove the cheapest known node
|
// remove the cheapest known node
|
||||||
NodeInfo info = uptight.remove(uptight.size()-1);
|
NodeInfo<T, V> info = uptight.remove(uptight.size()-1);
|
||||||
// make a note that it is now relaxed
|
// make a note that it is now relaxed
|
||||||
relaxed.add(info.node);
|
relaxed.add(info.node);
|
||||||
// relax its uptight neighbors
|
// relax its uptight neighbors
|
||||||
List<Object> edges = graph.getEdges(info.node);
|
List<V> edges = graph.getEdges(info.node);
|
||||||
for (int ii = 0, ll = edges.size(); ii < ll; ii++) {
|
for (int ii = 0, ll = edges.size(); ii < ll; ii++) {
|
||||||
Object edge = edges.get(ii);
|
V edge = edges.get(ii);
|
||||||
Object onode = graph.getOpposite(edge, info.node);
|
T onode = graph.getOpposite(edge, info.node);
|
||||||
if (relaxed.contains(onode)) {
|
if (relaxed.contains(onode)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if the path through this node to its neighbor is
|
// if the path through this node to its neighbor is cheaper than the existing known
|
||||||
// cheaper than the existing known shortest path, update
|
// shortest path, update the neighbor to reflect this new shorter path
|
||||||
// the neighbor to reflect this new shorter path
|
NodeInfo<T, V> oinfo = nodes.get(onode);
|
||||||
NodeInfo oinfo = nodes.get(onode);
|
|
||||||
int weight = graph.computeWeight(edge, info.node);
|
int weight = graph.computeWeight(edge, info.node);
|
||||||
if (oinfo.weightTo > info.weightTo + weight) {
|
if (oinfo.weightTo > info.weightTo + weight) {
|
||||||
oinfo.weightTo = info.weightTo + weight;
|
oinfo.weightTo = info.weightTo + weight;
|
||||||
@@ -113,8 +108,8 @@ public class ShortestPath
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now trace the path from the final node back to the start
|
// now trace the path from the final node back to the start
|
||||||
ArrayList<Object> path = new ArrayList<Object>();
|
ArrayList<V> path = new ArrayList<V>();
|
||||||
NodeInfo info = nodes.get(end);
|
NodeInfo<T, V> info = nodes.get(end);
|
||||||
while (info.edgeTo != null) {
|
while (info.edgeTo != null) {
|
||||||
path.add(0, info.edgeTo);
|
path.add(0, info.edgeTo);
|
||||||
info = nodes.get(graph.getOpposite(info.edgeTo, info.node));
|
info = nodes.get(graph.getOpposite(info.edgeTo, info.node));
|
||||||
@@ -123,20 +118,19 @@ public class ShortestPath
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Used to maintain information during the shortest path search. */
|
/** Used to maintain information during the shortest path search. */
|
||||||
protected static final class NodeInfo implements Comparable<NodeInfo>
|
protected static final class NodeInfo<T, V> implements Comparable<NodeInfo<T, V>>
|
||||||
{
|
{
|
||||||
/** The node for which we're representing information. */
|
/** The node for which we're representing information. */
|
||||||
public Object node;
|
public T node;
|
||||||
|
|
||||||
/** The cumulative weight to this node from the source. */
|
/** The cumulative weight to this node from the source. */
|
||||||
public int weightTo = Integer.MAX_VALUE / 4;
|
public int weightTo = Integer.MAX_VALUE / 4;
|
||||||
|
|
||||||
/** The edge followed to reach this node along the shortest path. */
|
/** The edge followed to reach this node along the shortest path. */
|
||||||
public Object edgeTo;
|
public V edgeTo;
|
||||||
|
|
||||||
/** We order ourselves by the cumulative weight to this node. */
|
/** We order ourselves by the cumulative weight to this node. */
|
||||||
public int compareTo (NodeInfo o)
|
public int compareTo (NodeInfo<T, V> o) {
|
||||||
{
|
|
||||||
return o.weightTo - weightTo;
|
return o.weightTo - weightTo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user