--- /dev/null
+/*
+* Copyright (c) 2003, the JUNG Project and the Regents of the University
+* of California
+* All rights reserved.
+*
+* This software is open-source under the BSD license; see either
+* "license.txt" or
+* http://jung.sourceforge.net/license.txt for a description.
+*/
+package edu.uci.ics.jung.algorithms.shortestpath;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import edu.uci.ics.jung.graph.Hypergraph;
+
+/**
+ * Computes the shortest path distances for graphs whose edges are not weighted (using BFS).
+ *
+ * @author Scott White
+ */
+public class UnweightedShortestPath<V, E>
+ implements ShortestPath<V,E>, Distance<V>
+{
+ private Map<V,Map<V,Number>> mDistanceMap;
+ private Map<V,Map<V,E>> mIncomingEdgeMap;
+ private Hypergraph<V,E> mGraph;
+ private Map<V, Number> distances = new HashMap<V,Number>();
+
+ /**
+ * Constructs and initializes algorithm
+ * @param g the graph
+ */
+ public UnweightedShortestPath(Hypergraph<V,E> g)
+ {
+ mDistanceMap = new HashMap<V,Map<V,Number>>();
+ mIncomingEdgeMap = new HashMap<V,Map<V,E>>();
+ mGraph = g;
+ }
+
+ /**
+ * @see edu.uci.ics.jung.algorithms.shortestpath.Distance#getDistance(Object, Object)
+ */
+ public Number getDistance(V source, V target)
+ {
+ Map<V, Number> sourceSPMap = getDistanceMap(source);
+ return sourceSPMap.get(target);
+ }
+
+ /**
+ * @see edu.uci.ics.jung.algorithms.shortestpath.Distance#getDistanceMap(Object)
+ */
+ public Map<V,Number> getDistanceMap(V source)
+ {
+ Map<V,Number> sourceSPMap = mDistanceMap.get(source);
+ if (sourceSPMap == null)
+ {
+ computeShortestPathsFromSource(source);
+ sourceSPMap = mDistanceMap.get(source);
+ }
+ return sourceSPMap;
+ }
+
+ /**
+ * @see edu.uci.ics.jung.algorithms.shortestpath.ShortestPath#getIncomingEdgeMap(Object)
+ */
+ public Map<V,E> getIncomingEdgeMap(V source)
+ {
+ Map<V,E> sourceIEMap = mIncomingEdgeMap.get(source);
+ if (sourceIEMap == null)
+ {
+ computeShortestPathsFromSource(source);
+ sourceIEMap = mIncomingEdgeMap.get(source);
+ }
+ return sourceIEMap;
+ }
+
+
+ /**
+ * Computes the shortest path distances from a given node to all other nodes.
+ * @param source the source node
+ */
+ private void computeShortestPathsFromSource(V source)
+ {
+ BFSDistanceLabeler<V,E> labeler = new BFSDistanceLabeler<V,E>();
+ labeler.labelDistances(mGraph, source);
+ distances = labeler.getDistanceDecorator();
+ Map<V,Number> currentSourceSPMap = new HashMap<V,Number>();
+ Map<V,E> currentSourceEdgeMap = new HashMap<V,E>();
+
+ for(V vertex : mGraph.getVertices()) {
+
+ Number distanceVal = distances.get(vertex);
+ // BFSDistanceLabeler uses -1 to indicate unreachable vertices;
+ // don't bother to store unreachable vertices
+ if (distanceVal != null && distanceVal.intValue() >= 0)
+ {
+ currentSourceSPMap.put(vertex, distanceVal);
+ int minDistance = distanceVal.intValue();
+ for(E incomingEdge : mGraph.getInEdges(vertex))
+ {
+ for (V neighbor : mGraph.getIncidentVertices(incomingEdge))
+ {
+ if (neighbor.equals(vertex))
+ continue;
+// V neighbor = mGraph.getOpposite(vertex, incomingEdge);
+
+ Number predDistanceVal = distances.get(neighbor);
+
+ int pred_distance = predDistanceVal.intValue();
+ if (pred_distance < minDistance && pred_distance >= 0)
+ {
+ minDistance = predDistanceVal.intValue();
+ currentSourceEdgeMap.put(vertex, incomingEdge);
+ }
+ }
+ }
+ }
+ }
+ mDistanceMap.put(source, currentSourceSPMap);
+ mIncomingEdgeMap.put(source, currentSourceEdgeMap);
+ }
+
+ /**
+ * Clears all stored distances for this instance.
+ * Should be called whenever the graph is modified (edge weights
+ * changed or edges added/removed). If the user knows that
+ * some currently calculated distances are unaffected by a
+ * change, <code>reset(V)</code> may be appropriate instead.
+ *
+ * @see #reset(Object)
+ */
+ public void reset()
+ {
+ mDistanceMap.clear();
+ mIncomingEdgeMap.clear();
+ }
+
+ /**
+ * Clears all stored distances for the specified source vertex
+ * <code>source</code>. Should be called whenever the stored distances
+ * from this vertex are invalidated by changes to the graph.
+ *
+ * @see #reset()
+ */
+ public void reset(V v)
+ {
+ mDistanceMap.remove(v);
+ mIncomingEdgeMap.remove(v);
+ }
+}