/* * 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. *

* Running time is: O(m) * @author Scott White */ public class BFSDistanceLabeler { private Map distanceDecorator = new HashMap(); private List mCurrentList; private Set mUnvisitedVertices; private List mVerticesInOrderVisited; private Map> 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>(); } /** * Returns the list of vertices visited in order of traversal * @return the list of vertices */ public List getVerticesInOrderVisited() { return mVerticesInOrderVisited; } /** * Returns the set of all vertices that were not visited * @return the list of unvisited vertices */ public Set 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 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 getPredecessors(V v) { return mPredecessorMap.get(v); } protected void initialize(Hypergraph g, Set rootSet) { mVerticesInOrderVisited = new ArrayList(); mUnvisitedVertices = new HashSet(); for(V currentVertex : g.getVertices()) { mUnvisitedVertices.add(currentVertex); mPredecessorMap.put(currentVertex,new HashSet()); } mCurrentList = new ArrayList(); 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 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 graph, Set rootSet) { initialize(graph,rootSet); int distance = 1; while (true) { List newList = new ArrayList(); 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 graph, V root) { labelDistances(graph, Collections.singleton(root)); } private void visitNewVertex(V predecessor, V neighbor, int distance, List 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 getDistanceDecorator() { return distanceDecorator; } }