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