View Javadoc
1   /*
2   * Copyright (c) 2003, The JUNG Authors 
3   *
4   * All rights reserved.
5   *
6   * This software is open-source under the BSD license; see either
7   * "license.txt" or
8   * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
9   */
10  package edu.uci.ics.jung.algorithms.shortestpath;
11  
12  
13  import java.util.ArrayList;
14  import java.util.Collections;
15  import java.util.HashMap;
16  import java.util.HashSet;
17  import java.util.List;
18  import java.util.Map;
19  import java.util.Set;
20  
21  import edu.uci.ics.jung.graph.Hypergraph;
22  
23  /**
24   * Labels each node in the graph according to the BFS distance from the start node(s). If nodes are unreachable, then
25   * they are assigned a distance of -1.
26   * All nodes traversed at step k are marked as predecessors of their successors traversed at step k+1.
27   * <p>
28   * Running time is: O(m)
29   * @author Scott White
30   */
31  public class BFSDistanceLabeler<V, E> {
32  
33      private Map<V, Number> distanceDecorator = new HashMap<V,Number>();
34      private List<V> mCurrentList;
35      private Set<V> mUnvisitedVertices;
36      private List<V> mVerticesInOrderVisited;
37      private Map<V,HashSet<V>> mPredecessorMap;
38  
39  	/**
40  	 * Creates a new BFS labeler for the specified graph and root set
41  	 * The distances are stored in the corresponding Vertex objects and are of type MutableInteger
42  	 */
43  	public BFSDistanceLabeler() {
44  		mPredecessorMap = new HashMap<V,HashSet<V>>();
45  	}
46  
47      /**
48       * Returns the list of vertices visited in order of traversal
49       * @return the list of vertices
50       */
51      public List<V> getVerticesInOrderVisited() {
52          return mVerticesInOrderVisited;
53      }
54  
55      /**
56       * Returns the set of all vertices that were not visited
57       * @return the list of unvisited vertices
58       */
59      public Set<V> getUnvisitedVertices() {
60          return mUnvisitedVertices;
61      }
62  
63      /**
64       * Given a vertex, returns the shortest distance from any node in the root set to v
65       * @param g the graph in which the distances are to be measured
66       * @param v the vertex whose distance is to be retrieved
67       * @return the shortest distance from any node in the root set to v
68       */
69      public int getDistance(Hypergraph<V,E> g, V v) {
70          if (!g.getVertices().contains(v)) {
71              throw new IllegalArgumentException("Vertex is not contained in the graph.");
72          }
73  
74          return distanceDecorator.get(v).intValue();
75      }
76  
77      /**
78       * Returns set of predecessors of the given vertex
79       * @param v the vertex whose predecessors are to be retrieved
80       * @return the set of predecessors
81       */
82      public Set<V> getPredecessors(V v) {
83          return mPredecessorMap.get(v);
84      }
85  
86      protected void initialize(Hypergraph<V,E> g, Set<V> rootSet) {
87          mVerticesInOrderVisited = new ArrayList<V>();
88          mUnvisitedVertices = new HashSet<V>();
89          for(V currentVertex : g.getVertices()) {
90              mUnvisitedVertices.add(currentVertex);
91              mPredecessorMap.put(currentVertex,new HashSet<V>());
92          }
93  
94          mCurrentList = new ArrayList<V>();
95          for(V v : rootSet) {
96              distanceDecorator.put(v, new Integer(0));
97              mCurrentList.add(v);
98              mUnvisitedVertices.remove(v);
99              mVerticesInOrderVisited.add(v);
100         }
101     }
102 
103     private void addPredecessor(V predecessor,V sucessor) {
104         HashSet<V> predecessors = mPredecessorMap.get(sucessor);
105         predecessors.add(predecessor);
106     }
107 
108     /**
109      * Computes the distances of all the node from the starting root nodes. If there is more than one root node
110      * the minimum distance from each root node is used as the designated distance to a given node. Also keeps track
111      * of the predecessors of each node traversed as well as the order of nodes traversed.
112      * @param graph the graph to label
113      * @param rootSet the set of starting vertices to traverse from
114      */
115     public void labelDistances(Hypergraph<V,E> graph, Set<V> rootSet) {
116 
117         initialize(graph,rootSet);
118 
119         int distance = 1;
120         while (true) {
121             List<V> newList = new ArrayList<V>();
122             for(V currentVertex : mCurrentList) {
123             	if(graph.containsVertex(currentVertex)) {
124             		for(V next : graph.getSuccessors(currentVertex)) {
125             			visitNewVertex(currentVertex,next, distance, newList);
126             		}
127             	}
128             }
129             if (newList.size() == 0) break;
130             mCurrentList = newList;
131             distance++;
132         }
133 
134         for(V v : mUnvisitedVertices) {
135             distanceDecorator.put(v,new Integer(-1));
136         }
137     }
138 
139     /**
140      * Computes the distances of all the node from the specified root node. Also keeps track
141      * of the predecessors of each node traversed as well as the order of nodes traversed.
142      *  @param graph the graph to label
143      * @param root the single starting vertex to traverse from
144      */
145     public void labelDistances(Hypergraph<V,E> graph, V root) {
146         labelDistances(graph, Collections.singleton(root));
147     }
148 
149     private void visitNewVertex(V predecessor, V neighbor, int distance, List<V> newList) {
150         if (mUnvisitedVertices.contains(neighbor)) {
151             distanceDecorator.put(neighbor, new Integer(distance));
152             newList.add(neighbor);
153             mVerticesInOrderVisited.add(neighbor);
154             mUnvisitedVertices.remove(neighbor);
155         }
156         int predecessorDistance = distanceDecorator.get(predecessor).intValue();
157         int successorDistance = distanceDecorator.get(neighbor).intValue();
158         if (predecessorDistance < successorDistance) {
159             addPredecessor(predecessor,neighbor);
160         }
161     }
162 
163     /**
164      * Must be called after {@code labelDistances} in order to contain valid data.
165      * @return a map from vertices to minimum distances from the original source(s)
166      */
167     public Map<V, Number> getDistanceDecorator() {
168         return distanceDecorator;
169     }
170 }