TreeTraverser.java revision 3ecfa412eddc4b084663f38d562537b86b9734d5
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
17package com.google.common.collect;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.annotations.Beta;
22import com.google.common.annotations.GwtCompatible;
23
24import java.util.ArrayDeque;
25import java.util.Deque;
26import java.util.Iterator;
27import 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)
54public 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   */
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   */
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