--- /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.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import edu.uci.ics.jung.graph.Hypergraph;
+
+/**
+ * Labels each node in the graph according to the BFS distance from the start node(s). If nodes are unreachable, then
+ * they are assigned a distance of -1.
+ * All nodes traversed at step k are marked as predecessors of their successors traversed at step k+1.
+ * <p>
+ * Running time is: O(m)
+ * @author Scott White
+ */
+public class BFSDistanceLabeler<V, E> {
+
+ private Map<V, Number> distanceDecorator = new HashMap<V,Number>();
+ private List<V> mCurrentList;
+ private Set<V> mUnvisitedVertices;
+ private List<V> mVerticesInOrderVisited;
+ private Map<V,HashSet<V>> mPredecessorMap;
+
+ /**
+ * Creates a new BFS labeler for the specified graph and root set
+ * The distances are stored in the corresponding Vertex objects and are of type MutableInteger
+ */
+ public BFSDistanceLabeler() {
+ mPredecessorMap = new HashMap<V,HashSet<V>>();
+ }
+
+ /**
+ * Returns the list of vertices visited in order of traversal
+ * @return the list of vertices
+ */
+ public List<V> getVerticesInOrderVisited() {
+ return mVerticesInOrderVisited;
+ }
+
+ /**
+ * Returns the set of all vertices that were not visited
+ * @return the list of unvisited vertices
+ */
+ public Set<V> getUnvisitedVertices() {
+ return mUnvisitedVertices;
+ }
+
+ /**
+ * Given a vertex, returns the shortest distance from any node in the root set to v
+ * @param v the vertex whose distance is to be retrieved
+ * @return the shortest distance from any node in the root set to v
+ */
+ public int getDistance(Hypergraph<V,E> g, V v) {
+ if (!g.getVertices().contains(v)) {
+ throw new IllegalArgumentException("Vertex is not contained in the graph.");
+ }
+
+ return distanceDecorator.get(v).intValue();
+ }
+
+ /**
+ * Returns set of predecessors of the given vertex
+ * @param v the vertex whose predecessors are to be retrieved
+ * @return the set of predecessors
+ */
+ public Set<V> getPredecessors(V v) {
+ return mPredecessorMap.get(v);
+ }
+
+ protected void initialize(Hypergraph<V,E> g, Set<V> rootSet) {
+ mVerticesInOrderVisited = new ArrayList<V>();
+ mUnvisitedVertices = new HashSet<V>();
+ for(V currentVertex : g.getVertices()) {
+ mUnvisitedVertices.add(currentVertex);
+ mPredecessorMap.put(currentVertex,new HashSet<V>());
+ }
+
+ mCurrentList = new ArrayList<V>();
+ for(V v : rootSet) {
+ distanceDecorator.put(v, new Integer(0));
+ mCurrentList.add(v);
+ mUnvisitedVertices.remove(v);
+ mVerticesInOrderVisited.add(v);
+ }
+ }
+
+ private void addPredecessor(V predecessor,V sucessor) {
+ HashSet<V> predecessors = mPredecessorMap.get(sucessor);
+ predecessors.add(predecessor);
+ }
+
+ /**
+ * Computes the distances of all the node from the starting root nodes. If there is more than one root node
+ * the minimum distance from each root node is used as the designated distance to a given node. Also keeps track
+ * of the predecessors of each node traversed as well as the order of nodes traversed.
+ * @param graph the graph to label
+ * @param rootSet the set of starting vertices to traverse from
+ */
+ public void labelDistances(Hypergraph<V,E> graph, Set<V> rootSet) {
+
+ initialize(graph,rootSet);
+
+ int distance = 1;
+ while (true) {
+ List<V> newList = new ArrayList<V>();
+ for(V currentVertex : mCurrentList) {
+ if(graph.containsVertex(currentVertex)) {
+ for(V next : graph.getSuccessors(currentVertex)) {
+ visitNewVertex(currentVertex,next, distance, newList);
+ }
+ }
+ }
+ if (newList.size() == 0) break;
+ mCurrentList = newList;
+ distance++;
+ }
+
+ for(V v : mUnvisitedVertices) {
+ distanceDecorator.put(v,new Integer(-1));
+ }
+ }
+
+ /**
+ * Computes the distances of all the node from the specified root node. Also keeps track
+ * of the predecessors of each node traversed as well as the order of nodes traversed.
+ * @param graph the graph to label
+ * @param root the single starting vertex to traverse from
+ */
+ public void labelDistances(Hypergraph<V,E> graph, V root) {
+ labelDistances(graph, Collections.singleton(root));
+ }
+
+ private void visitNewVertex(V predecessor, V neighbor, int distance, List<V> newList) {
+ if (mUnvisitedVertices.contains(neighbor)) {
+ distanceDecorator.put(neighbor, new Integer(distance));
+ newList.add(neighbor);
+ mVerticesInOrderVisited.add(neighbor);
+ mUnvisitedVertices.remove(neighbor);
+ }
+ int predecessorDistance = distanceDecorator.get(predecessor).intValue();
+ int successorDistance = distanceDecorator.get(neighbor).intValue();
+ if (predecessorDistance < successorDistance) {
+ addPredecessor(predecessor,neighbor);
+ }
+ }
+
+ /**
+ * Returns a map from vertices to minimum distances from the original source(s).
+ * Must be called after {@code labelDistances} in order to contain valid data.
+ */
+ public Map<V, Number> getDistanceDecorator() {
+ return distanceDecorator;
+ }
+}