• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.annotations.Beta;
22 import com.google.common.annotations.GwtCompatible;
23 
24 import java.util.ArrayDeque;
25 import java.util.Deque;
26 import java.util.Iterator;
27 import java.util.Queue;
28 
29 /**
30  * Views elements of a type {@code T} as nodes in a tree, and provides methods to traverse the trees
31  * induced by this traverser.
32  *
33  * <p>For example, the tree
34  *
35  * <pre>          {@code
36  *          h
37  *        / | \
38  *       /  e  \
39  *      d       g
40  *     /|\      |
41  *    / | \     f
42  *   a  b  c       }</pre>
43  *
44  * <p>can be iterated over in preorder (hdabcegf), postorder (abcdefgh), or breadth-first order
45  * (hdegabcf).
46  *
47  * <p>Null nodes are strictly forbidden.
48  *
49  * @author Louis Wasserman
50  * @since 15.0
51  */
52 @Beta
53 @GwtCompatible(emulated = true)
54 public abstract class TreeTraverser<T> {
55   // TODO(user): make this GWT-compatible when we've checked in ArrayDeque emulation
56 
57   /**
58    * Returns the children of the specified node.  Must not contain null.
59    */
children(T root)60   public abstract Iterable<T> children(T root);
61 
62   /**
63    * Returns an unmodifiable iterable over the nodes in a tree structure, using pre-order
64    * traversal. That is, each node's subtrees are traversed after the node itself is returned.
65    *
66    * <p>No guarantees are made about the behavior of the traversal when nodes change while
67    * iteration is in progress or when the iterators generated by {@link #children} are advanced.
68    */
preOrderTraversal(final T root)69   public final FluentIterable<T> preOrderTraversal(final T root) {
70     checkNotNull(root);
71     return new FluentIterable<T>() {
72       @Override
73       public UnmodifiableIterator<T> iterator() {
74         return preOrderIterator(root);
75       }
76     };
77   }
78 
79   // overridden in BinaryTreeTraverser
80   UnmodifiableIterator<T> preOrderIterator(T root) {
81     return new PreOrderIterator(root);
82   }
83 
84   private final class PreOrderIterator extends UnmodifiableIterator<T> {
85     private final Deque<Iterator<T>> stack;
86 
87     PreOrderIterator(T root) {
88       this.stack = new ArrayDeque<Iterator<T>>();
89       stack.addLast(Iterators.singletonIterator(checkNotNull(root)));
90     }
91 
92     @Override
93     public boolean hasNext() {
94       return !stack.isEmpty();
95     }
96 
97     @Override
98     public T next() {
99       Iterator<T> itr = stack.getLast(); // throws NSEE if empty
100       T result = checkNotNull(itr.next());
101       if (!itr.hasNext()) {
102         stack.removeLast();
103       }
104       Iterator<T> childItr = children(result).iterator();
105       if (childItr.hasNext()) {
106         stack.addLast(childItr);
107       }
108       return result;
109     }
110   }
111 
112   /**
113    * Returns an unmodifiable iterable over the nodes in a tree structure, using post-order
114    * traversal. That is, each node's subtrees are traversed before the node itself is returned.
115    *
116    * <p>No guarantees are made about the behavior of the traversal when nodes change while
117    * iteration is in progress or when the iterators generated by {@link #children} are advanced.
118    */
119   public final FluentIterable<T> postOrderTraversal(final T root) {
120     checkNotNull(root);
121     return new FluentIterable<T>() {
122       @Override
123       public UnmodifiableIterator<T> iterator() {
124         return postOrderIterator(root);
125       }
126     };
127   }
128 
129   // overridden in BinaryTreeTraverser
130   UnmodifiableIterator<T> postOrderIterator(T root) {
131     return new PostOrderIterator(root);
132   }
133 
134   private static final class PostOrderNode<T> {
135     final T root;
136     final Iterator<T> childIterator;
137 
138     PostOrderNode(T root, Iterator<T> childIterator) {
139       this.root = checkNotNull(root);
140       this.childIterator = checkNotNull(childIterator);
141     }
142   }
143 
144   private final class PostOrderIterator extends AbstractIterator<T> {
145     private final ArrayDeque<PostOrderNode<T>> stack;
146 
147     PostOrderIterator(T root) {
148       this.stack = new ArrayDeque<PostOrderNode<T>>();
149       stack.addLast(expand(root));
150     }
151 
152     @Override
153     protected T computeNext() {
154       while (!stack.isEmpty()) {
155         PostOrderNode<T> top = stack.getLast();
156         if (top.childIterator.hasNext()) {
157           T child = top.childIterator.next();
158           stack.addLast(expand(child));
159         } else {
160           stack.removeLast();
161           return top.root;
162         }
163       }
164       return endOfData();
165     }
166 
167     private PostOrderNode<T> expand(T t) {
168       return new PostOrderNode<T>(t, children(t).iterator());
169     }
170   }
171 
172   /**
173    * Returns an unmodifiable iterable over the nodes in a tree structure, using breadth-first
174    * traversal. That is, all the nodes of depth 0 are returned, then depth 1, then 2, and so on.
175    *
176    * <p>No guarantees are made about the behavior of the traversal when nodes change while
177    * iteration is in progress or when the iterators generated by {@link #children} are advanced.
178    */
179   public final FluentIterable<T> breadthFirstTraversal(final T root) {
180     checkNotNull(root);
181     return new FluentIterable<T>() {
182       @Override
183       public UnmodifiableIterator<T> iterator() {
184         return new BreadthFirstIterator(root);
185       }
186     };
187   }
188 
189   private final class BreadthFirstIterator extends UnmodifiableIterator<T>
190       implements PeekingIterator<T> {
191     private final Queue<T> queue;
192 
193     BreadthFirstIterator(T root) {
194       this.queue = new ArrayDeque<T>();
195       queue.add(root);
196     }
197 
198     @Override
199     public boolean hasNext() {
200       return !queue.isEmpty();
201     }
202 
203     @Override
204     public T peek() {
205       return queue.element();
206     }
207 
208     @Override
209     public T next() {
210       T result = queue.remove();
211       Iterables.addAll(queue, children(result));
212       return result;
213     }
214   }
215 }
216