/* * 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, Integer.valueOf(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, Integer.valueOf(-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, Integer.valueOf(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; } }