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;
|
||||
|
||||
/**
|
||||
* Implements Dijkstra's algorithm for finding the shortest path between
|
||||
* two nodes in a weighted graph. The code assumes that the caller
|
||||
* represents their nodes and edges as objects which can be compared and
|
||||
* hashed (via {@link Object#equals} and {@link Object#hashCode}) other
|
||||
* necessary information is obtained through a special interface {@link
|
||||
* Graph} implemented by the caller to enumerate edges and compute
|
||||
* weights.
|
||||
* Implements Dijkstra's algorithm for finding the shortest path between two nodes in a weighted
|
||||
* graph. The code assumes that the caller represents their nodes and edges as objects which can
|
||||
* be compared and hashed (via {@link Object#equals} and {@link Object#hashCode}) other necessary
|
||||
* information is obtained through a special interface {@link Graph} implemented by the caller to
|
||||
* enumerate edges and compute weights.
|
||||
*/
|
||||
public class ShortestPath
|
||||
{
|
||||
/** A caller must implement this interface to provide the information
|
||||
* needed to define the graph and compute the shortest path. */
|
||||
public interface Graph
|
||||
/** A caller must implement this interface to provide the information needed to define the
|
||||
* graph and compute the shortest path.
|
||||
*/
|
||||
public interface Graph<T, V>
|
||||
{
|
||||
/** Enumerates all nodes in the graph. */
|
||||
public Iterator<Object> enumerateNodes ();
|
||||
public Iterator<T> enumerateNodes ();
|
||||
|
||||
/** 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
|
||||
* direction established by the supplied starting node. */
|
||||
public int computeWeight (Object edge, Object start);
|
||||
/** Returns the weight associated with the supplied edge in the direction established by
|
||||
* the supplied starting node. */
|
||||
public int computeWeight (V edge, T start);
|
||||
|
||||
/** 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
|
||||
* ending nodes using Dijkstra's algorithm. This implementation
|
||||
* assumes that the graph is properly formed and may behave strangely
|
||||
* or throw an exception if provided with an invalid graph.
|
||||
* Computes the shortest path between the specified starting and ending nodes using Dijkstra's
|
||||
* algorithm. This implementation assumes that the graph is properly formed and may behave
|
||||
* strangely or throw an exception if provided with an invalid graph.
|
||||
*
|
||||
* @return a list of the edges that must be followed to traverse from the
|
||||
* starting node to the ending node. This list may be empty if the graph is
|
||||
* improperly formed.
|
||||
* @return a list of the edges that must be followed to traverse from the starting node to the
|
||||
* ending node. This list may be empty if the graph is 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>();
|
||||
HashSet<Object> relaxed = new HashSet<Object>();
|
||||
ComparableArrayList<NodeInfo> uptight =
|
||||
new ComparableArrayList<NodeInfo>();
|
||||
HashMap<T, NodeInfo<T, V>> nodes = new HashMap<T, NodeInfo<T, V>>();
|
||||
HashSet<T> relaxed = new HashSet<T>();
|
||||
ComparableArrayList<NodeInfo<T, V>> uptight = new ComparableArrayList<NodeInfo<T, V>>();
|
||||
|
||||
// initialize our searching info
|
||||
for (Iterator<Object> iter = graph.enumerateNodes(); iter.hasNext(); ) {
|
||||
NodeInfo info = new NodeInfo();
|
||||
for (Iterator<T> iter = graph.enumerateNodes(); iter.hasNext(); ) {
|
||||
NodeInfo<T, V> info = new NodeInfo<T, V>();
|
||||
info.node = iter.next();
|
||||
if (info.node == start) {
|
||||
info.weightTo = 0;
|
||||
@@ -87,21 +83,20 @@ public class ShortestPath
|
||||
// now execute the main part of the search
|
||||
while (uptight.size() > 0) {
|
||||
// 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
|
||||
relaxed.add(info.node);
|
||||
// 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++) {
|
||||
Object edge = edges.get(ii);
|
||||
Object onode = graph.getOpposite(edge, info.node);
|
||||
V edge = edges.get(ii);
|
||||
T onode = graph.getOpposite(edge, info.node);
|
||||
if (relaxed.contains(onode)) {
|
||||
continue;
|
||||
}
|
||||
// if the path through this node to its neighbor is
|
||||
// cheaper than the existing known shortest path, update
|
||||
// the neighbor to reflect this new shorter path
|
||||
NodeInfo oinfo = nodes.get(onode);
|
||||
// if the path through this node to its neighbor is cheaper than the existing known
|
||||
// shortest path, update the neighbor to reflect this new shorter path
|
||||
NodeInfo<T, V> oinfo = nodes.get(onode);
|
||||
int weight = graph.computeWeight(edge, info.node);
|
||||
if (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
|
||||
ArrayList<Object> path = new ArrayList<Object>();
|
||||
NodeInfo info = nodes.get(end);
|
||||
ArrayList<V> path = new ArrayList<V>();
|
||||
NodeInfo<T, V> info = nodes.get(end);
|
||||
while (info.edgeTo != null) {
|
||||
path.add(0, info.edgeTo);
|
||||
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. */
|
||||
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. */
|
||||
public Object node;
|
||||
public T node;
|
||||
|
||||
/** The cumulative weight to this node from the source. */
|
||||
public int weightTo = Integer.MAX_VALUE / 4;
|
||||
|
||||
/** 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. */
|
||||
public int compareTo (NodeInfo o)
|
||||
{
|
||||
public int compareTo (NodeInfo<T, V> o) {
|
||||
return o.weightTo - weightTo;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user