From 75a28c890c05a6d87f38aaa38a726ffe34a5a914 Mon Sep 17 00:00:00 2001 From: samskivert Date: Tue, 9 Jun 2009 18:36:20 +0000 Subject: [PATCH] Patch from Dave to genericize ShortestPath. git-svn-id: https://samskivert.googlecode.com/svn/trunk@2574 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../com/samskivert/util/ShortestPath.java | 84 +++++++++---------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/src/java/com/samskivert/util/ShortestPath.java b/src/java/com/samskivert/util/ShortestPath.java index 1ab3184f..1be79576 100644 --- a/src/java/com/samskivert/util/ShortestPath.java +++ b/src/java/com/samskivert/util/ShortestPath.java @@ -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 { /** Enumerates all nodes in the graph. */ - public Iterator enumerateNodes (); + public Iterator enumerateNodes (); /** Returns the list of the edges for the specified node. */ - public List getEdges (Object node); + public List 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 compute (Graph graph, Object start, Object end) + public static List compute (Graph graph, T start, T end) { - HashMap nodes = new HashMap(); - HashSet relaxed = new HashSet(); - ComparableArrayList uptight = - new ComparableArrayList(); + HashMap> nodes = new HashMap>(); + HashSet relaxed = new HashSet(); + ComparableArrayList> uptight = new ComparableArrayList>(); // initialize our searching info - for (Iterator iter = graph.enumerateNodes(); iter.hasNext(); ) { - NodeInfo info = new NodeInfo(); + for (Iterator iter = graph.enumerateNodes(); iter.hasNext(); ) { + NodeInfo info = new NodeInfo(); 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 info = uptight.remove(uptight.size()-1); // make a note that it is now relaxed relaxed.add(info.node); // relax its uptight neighbors - List edges = graph.getEdges(info.node); + List 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 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 path = new ArrayList(); - NodeInfo info = nodes.get(end); + ArrayList path = new ArrayList(); + NodeInfo 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 + protected static final class NodeInfo implements Comparable> { /** 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 o) { return o.weightTo - weightTo; } }