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