View Javadoc
1   package edu.uci.ics.jung.graph;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.HashMap;
7   import java.util.List;
8   import java.util.Map;
9   
10  import com.google.common.base.Supplier;
11  
12  import edu.uci.ics.jung.graph.util.EdgeType;
13  import edu.uci.ics.jung.graph.util.Pair;
14  
15  /**
16   * An implementation of <code>Tree</code> that delegates to
17   * a specified instance of <code>DirectedGraph</code>.
18   * @author Tom Nelson
19   *
20   * @param <V> the vertex type
21   * @param <E> the edge type
22   */
23  @SuppressWarnings("serial")
24  public class DelegateTree<V,E> extends GraphDecorator<V,E> implements Tree<V,E>
25  {
26      /**
27       * @param <V> the vertex type for the graph Supplier
28       * @param <E> the edge type for the graph Supplier
29       * @return a {@code Supplier} that creates an instance of this graph type.
30       */
31      public static final <V,E> Supplier<Tree<V,E>> getFactory() {
32  		return new Supplier<Tree<V,E>> () {
33  			public Tree<V,E> get() {
34  				return new DelegateTree<V,E>(new DirectedSparseMultigraph<V,E>());
35  			}
36  		};
37  	}
38  
39  	protected V root;
40      protected Map<V, Integer> vertex_depths;
41      
42      /**
43       * Creates an instance.
44       */
45      public DelegateTree() {
46      	this(DirectedSparseMultigraph.<V,E>getFactory());
47      }
48  
49  	/**
50  	 * create an instance with passed values.
51  	 * @param graphFactory must create a DirectedGraph to use as a delegate
52  	 */
53  	public DelegateTree(Supplier<DirectedGraph<V,E>> graphFactory) {
54  		super(graphFactory.get());
55          this.vertex_depths = new HashMap<V, Integer>();
56  	}
57  	
58  	/**
59  	 * Creates a new <code>DelegateTree</code> which delegates to <code>graph</code>.
60  	 * Assumes that <code>graph</code> is already a tree; if it's not, future behavior
61  	 * of this instance is undefined.
62  	 * @param graph the graph to which this instance will delegate operations.
63  	 */
64  	public DelegateTree(DirectedGraph<V,E> graph) {
65  		super(graph);
66          this.vertex_depths = new HashMap<V, Integer>();
67  	}
68  	
69  	/**
70  	 * Add an edge to the tree, connecting v1, the parent and v2, the child.
71  	 * v1 must already exist in the tree, and v2 must not already exist
72  	 * the passed edge must be unique in the tree. Passing an edgeType
73  	 * other than EdgeType.DIRECTED may cause an illegal argument exception 
74  	 * in the delegate graph.
75  	 * 
76  	 * @param e a unique edge to add
77  	 * @param v1 the parent node
78  	 * @param v2 the child node
79  	 * @param edgeType should be EdgeType.DIRECTED
80  	 * @return true if this call mutates the underlying graph
81  	 * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object, edu.uci.ics.jung.graph.util.EdgeType)
82  	 */
83  	@Override
84  	public boolean addEdge(E e, V v1, V v2, EdgeType edgeType) {
85  		return addChild(e, v1, v2, edgeType);
86  	}
87  
88  	/**
89  	 * Add an edge to the tree, connecting v1, the parent and v2, the child.
90  	 * v1 must already exist in the tree, and v2 must not already exist
91  	 * the passed edge must be unique in the tree. 
92  	 * 
93  	 * @param e a unique edge to add
94  	 * @param v1 the parent node
95  	 * @param v2 the child node
96  	 * @return true if this call mutates the underlying graph
97  	 * @see edu.uci.ics.jung.graph.Graph#addEdge(java.lang.Object, java.lang.Object, java.lang.Object)
98  	 */
99  	@Override
100 	public boolean addEdge(E e, V v1, V v2) {
101 		return addChild(e, v1, v2);
102 	}
103 
104 	/**
105 	 * Will set the root of the Tree, only if the Tree is empty and the
106 	 * root is currently unset.
107 	 * 
108 	 * @param vertex the tree root to set
109 	 * @return true if this call mutates the underlying graph
110 	 * @see edu.uci.ics.jung.graph.Graph#addVertex(java.lang.Object)
111 	 * @throws UnsupportedOperationException if the root was previously set
112 	 */
113 	@Override
114 	public boolean addVertex(V vertex) {
115 		if(root == null) {
116 			this.root = vertex;
117             vertex_depths.put(vertex, 0);
118 			return delegate.addVertex(vertex);
119 		} else {
120 			throw new UnsupportedOperationException("Unless you are setting the root, use addChild()");
121 		}
122 	}
123 
124 	/**
125 	 * remove the passed node, and all nodes that are descendants of the
126 	 * passed node.
127 	 * @param vertex the vertex to remove
128 	 * @return <code>true</code> iff the tree was modified 
129 	 * @see edu.uci.ics.jung.graph.Graph#removeVertex(java.lang.Object)
130 	 */
131 	@Override
132 	public boolean removeVertex(V vertex) {
133 	    if (!delegate.containsVertex(vertex))
134 	        return false;
135 		for(V v : getChildren(vertex)) {
136 			removeVertex(v);
137             vertex_depths.remove(v);
138 		}
139         
140         // recalculate height
141 		vertex_depths.remove(vertex);
142 		return delegate.removeVertex(vertex);
143 	}
144 	
145 	/**
146 	 * add the passed child node as a child of parent.
147 	 * parent must exist in the tree, and child must not already exist.
148 	 * 
149 	 * @param edge the unique edge to connect the parent and child nodes
150 	 * @param parent the existing parent to attach the child to
151 	 * @param child the new child to add to the tree as a child of parent
152 	 * @param edgeType must be EdgeType.DIRECTED or the underlying graph may throw an exception
153 	 * @return whether this call mutates the underlying graph
154 	 */
155 	public boolean addChild(E edge, V parent, V child, EdgeType edgeType) {
156 		Collection<V> vertices = delegate.getVertices();
157 		if(vertices.contains(parent) == false) {
158 			throw new IllegalArgumentException("Tree must already contain parent "+parent);
159 		}
160 		if(vertices.contains(child)) {
161 			throw new IllegalArgumentException("Tree must not already contain child "+child);
162 		}
163         vertex_depths.put(child, vertex_depths.get(parent) + 1);
164 		return delegate.addEdge(edge, parent, child, edgeType);
165 	}
166 
167 	/**
168 	 * add the passed child node as a child of parent.
169 	 * parent must exist in the tree, and child must not already exist
170 	 * @param edge the unique edge to connect the parent and child nodes
171 	 * @param parent the existing parent to attach the child to
172 	 * @param child the new child to add to the tree as a child of parent
173 	 * @return whether this call mutates the underlying graph
174 	 */
175 	public boolean addChild(E edge, V parent, V child) {
176 		Collection<V> vertices = delegate.getVertices();
177 		if(vertices.contains(parent) == false) {
178 			throw new IllegalArgumentException("Tree must already contain parent "+parent);
179 		}
180 		if(vertices.contains(child)) {
181 			throw new IllegalArgumentException("Tree must not already contain child "+child);
182 		}
183         vertex_depths.put(child, vertex_depths.get(parent) + 1);
184 		return delegate.addEdge(edge, parent, child);
185 	}
186 	
187 	/**
188 	 * get the number of children of the passed parent node
189 	 */
190 	public int getChildCount(V parent) {
191 	    if (!delegate.containsVertex(parent))
192 	        return 0;
193 		return getChildren(parent).size();
194 	}
195 
196 	/**
197 	 * get the immediate children nodes of the passed parent
198 	 */
199 	public Collection<V> getChildren(V parent) {
200         if (!delegate.containsVertex(parent))
201             return null;
202 		return delegate.getSuccessors(parent);
203 	}
204 
205 	/**
206 	 * get the single parent node of the passed child
207 	 */
208 	public V getParent(V child) {
209         if (!delegate.containsVertex(child))
210             return null;
211 		Collection<V> predecessors = delegate.getPredecessors(child);
212 		if(predecessors.size() == 0) {
213 			return null;
214 		}
215 		return predecessors.iterator().next();
216 	}
217 
218 	/**
219 	 * Returns an ordered list of the nodes beginning at the root
220 	 * and ending at {@code vertex}, including all intermediate
221 	 * nodes.
222 	 * @param vertex the last node in the path from the root
223 	 * @return an ordered list of the nodes from root to child
224 	 */
225 	public List<V> getPath(V vertex) {
226         if (!delegate.containsVertex(vertex))
227             return null;
228 		List<V> vertex_to_root = new ArrayList<V>();
229 		vertex_to_root.add(vertex);
230 		V parent = getParent(vertex);
231 		while(parent != null) {
232 			vertex_to_root.add(parent);
233 			parent = getParent(parent);
234 		}
235 		// reverse list so that it goes from root to child
236 		List<V> root_to_vertex = new ArrayList<V>(vertex_to_root.size());
237 		for (int i = vertex_to_root.size() - 1; i >= 0; i--)
238 			root_to_vertex.add(vertex_to_root.get(i));
239 		return root_to_vertex;
240 	}
241 
242 	/**
243 	 * getter for the root of the tree
244 	 * @return the root
245 	 */
246 	public V getRoot() {
247 		return root;
248 	}
249 	
250 	/**
251 	 * sets the root to the passed value, only if the root is
252 	 * previously unset
253 	 * @param root the initial tree root
254 	 */
255 	public void setRoot(V root) {
256 		addVertex(root);
257 	}
258 
259 	/**
260 	 * removes a node from the tree, causing all descendants of
261 	 * the removed node also to be removed
262 	 * @param orphan the node to remove
263 	 * @return whether this call mutates the underlying graph
264 	 */
265 	public boolean removeChild(V orphan) {
266 		return removeVertex(orphan);
267 	}
268 
269 	/**
270 	 * computes and returns the depth of the tree from the
271 	 * root to the passed vertex
272 	 * 
273 	 * @param v the node who's depth is computed
274 	 * @return the depth to the passed node.
275 	 */
276 	public int getDepth(V v) {
277         return this.vertex_depths.get(v);
278 	}
279 
280 	/**
281 	 * Computes and returns the height of the tree.
282 	 * 
283 	 * @return the height
284 	 */
285 	public int getHeight() {
286 		int height = 0;
287 		for(V v : getVertices()) {
288 			height = Math.max(height, getDepth(v));
289 		}
290 		return height;
291 	}
292 
293 	/**
294 	 * @param v the vertex to test
295 	 * @return <code>true</code> if <code>v</code> is neither 
296      * a leaf nor the root of this tree
297 	 */
298 	public boolean isInternal(V v) {
299 	    if (!delegate.containsVertex(v))
300 	        return false;
301 		return isLeaf(v) == false && isRoot(v) == false;
302 	}
303 
304 	/**
305 	 * @param v the vertex to test
306 	 * @return <code>true</code> if {@code v} has no children
307 	 */
308 	public boolean isLeaf(V v) {
309         if (!delegate.containsVertex(v))
310             return false;
311 		return getChildren(v).size() == 0;
312 	}
313 
314 	/**
315 	 * @param v the vertex to test
316 	 * @return <code>true</code> if {@code v} has no parent
317 	 */
318 	public boolean isRoot(V v) {
319         if (!delegate.containsVertex(v))
320             return false;
321 		return getParent(v) == null;
322 	}
323 
324 	@Override
325     public int getIncidentCount(E edge)
326     {
327         if (!delegate.containsEdge(edge))
328             return 0;
329         // all edges in a tree connect exactly 2 vertices
330         return 2;
331     }
332     
333 	@SuppressWarnings("unchecked")
334   @Override
335 	public boolean addEdge(E edge, Collection<? extends V> vertices) {
336 		Pair<V> pair = null;
337 		if(vertices instanceof Pair) {
338 			pair = (Pair<V>)vertices;
339 		} else {
340 			pair = new Pair<V>(vertices);
341 		}
342 		return addEdge(edge, pair.getFirst(), pair.getSecond());
343 	}
344 	
345 	@Override
346 	public String toString() {
347 		return "Tree of "+delegate.toString();
348 	}
349 
350 	public Collection<Tree<V, E>> getTrees() {
351 		return Collections.<Tree<V,E>>singleton(this);
352 	}
353 
354   public Collection<E> getChildEdges(V vertex) {
355       return getOutEdges(vertex);
356   }
357 
358   public E getParentEdge(V vertex) {
359       return getInEdges(vertex).iterator().next();
360   }
361 }