001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import static com.google.common.base.Preconditions.checkNotNull; 020 021import com.google.common.annotations.Beta; 022import com.google.common.annotations.GwtCompatible; 023import com.google.common.base.Optional; 024import java.util.ArrayDeque; 025import java.util.BitSet; 026import java.util.Deque; 027import java.util.Iterator; 028import java.util.function.Consumer; 029 030/** 031 * A variant of {@link TreeTraverser} for binary trees, providing additional traversals specific to 032 * binary trees. 033 * 034 * @author Louis Wasserman 035 * @since 15.0 036 * @deprecated Use {@link com.google.common.graph.Traverser} instead. All instance methods except 037 * for {@link #inOrderTraversal} have their equivalent on the result of {@code 038 * Traverser.forTree(tree)} where {@code tree} implements {@code SuccessorsFunction}, which has 039 * a similar API as {@link #children}. 040 * <p>This class is scheduled to be removed in January 2018. 041 */ 042@Deprecated 043@Beta 044@GwtCompatible 045public abstract class BinaryTreeTraverser<T> extends TreeTraverser<T> { 046 047 /** 048 * Returns the left child of the specified node, or {@link Optional#absent()} if the specified 049 * node has no left child. 050 */ 051 public abstract Optional<T> leftChild(T root); 052 053 /** 054 * Returns the right child of the specified node, or {@link Optional#absent()} if the specified 055 * node has no right child. 056 */ 057 public abstract Optional<T> rightChild(T root); 058 059 /** Returns the children of this node, in left-to-right order. */ 060 @Override 061 public final Iterable<T> children(final T root) { 062 checkNotNull(root); 063 return new FluentIterable<T>() { 064 @Override 065 public Iterator<T> iterator() { 066 return new AbstractIterator<T>() { 067 boolean doneLeft; 068 boolean doneRight; 069 070 @Override 071 protected T computeNext() { 072 if (!doneLeft) { 073 doneLeft = true; 074 Optional<T> left = leftChild(root); 075 if (left.isPresent()) { 076 return left.get(); 077 } 078 } 079 if (!doneRight) { 080 doneRight = true; 081 Optional<T> right = rightChild(root); 082 if (right.isPresent()) { 083 return right.get(); 084 } 085 } 086 return endOfData(); 087 } 088 }; 089 } 090 091 @Override 092 public void forEach(Consumer<? super T> action) { 093 acceptIfPresent(action, leftChild(root)); 094 acceptIfPresent(action, rightChild(root)); 095 } 096 }; 097 } 098 099 @Override 100 UnmodifiableIterator<T> preOrderIterator(T root) { 101 return new PreOrderIterator(root); 102 } 103 104 /* 105 * Optimized implementation of preOrderIterator for binary trees. 106 */ 107 private final class PreOrderIterator extends UnmodifiableIterator<T> 108 implements PeekingIterator<T> { 109 private final Deque<T> stack; 110 111 PreOrderIterator(T root) { 112 this.stack = new ArrayDeque<T>(8); 113 stack.addLast(root); 114 } 115 116 @Override 117 public boolean hasNext() { 118 return !stack.isEmpty(); 119 } 120 121 @Override 122 public T next() { 123 T result = stack.removeLast(); 124 pushIfPresent(stack, rightChild(result)); 125 pushIfPresent(stack, leftChild(result)); 126 return result; 127 } 128 129 @Override 130 public T peek() { 131 return stack.getLast(); 132 } 133 } 134 135 @Override 136 UnmodifiableIterator<T> postOrderIterator(T root) { 137 return new PostOrderIterator(root); 138 } 139 140 /* 141 * Optimized implementation of postOrderIterator for binary trees. 142 */ 143 private final class PostOrderIterator extends UnmodifiableIterator<T> { 144 private final Deque<T> stack; 145 private final BitSet hasExpanded; 146 147 PostOrderIterator(T root) { 148 this.stack = new ArrayDeque<T>(8); 149 stack.addLast(root); 150 this.hasExpanded = new BitSet(); 151 } 152 153 @Override 154 public boolean hasNext() { 155 return !stack.isEmpty(); 156 } 157 158 @Override 159 public T next() { 160 while (true) { 161 T node = stack.getLast(); 162 boolean expandedNode = hasExpanded.get(stack.size() - 1); 163 if (expandedNode) { 164 stack.removeLast(); 165 hasExpanded.clear(stack.size()); 166 return node; 167 } else { 168 hasExpanded.set(stack.size() - 1); 169 pushIfPresent(stack, rightChild(node)); 170 pushIfPresent(stack, leftChild(node)); 171 } 172 } 173 } 174 } 175 176 // TODO(lowasser): see if any significant optimizations are possible for breadthFirstIterator 177 178 public final FluentIterable<T> inOrderTraversal(final T root) { 179 checkNotNull(root); 180 return new FluentIterable<T>() { 181 @Override 182 public UnmodifiableIterator<T> iterator() { 183 return new InOrderIterator(root); 184 } 185 186 @Override 187 public void forEach(Consumer<? super T> action) { 188 checkNotNull(action); 189 new Consumer<T>() { 190 @Override 191 public void accept(T t) { 192 acceptIfPresent(this, leftChild(t)); 193 action.accept(t); 194 acceptIfPresent(this, rightChild(t)); 195 } 196 }.accept(root); 197 } 198 }; 199 } 200 201 private final class InOrderIterator extends AbstractIterator<T> { 202 private final Deque<T> stack; 203 private final BitSet hasExpandedLeft; 204 205 InOrderIterator(T root) { 206 this.stack = new ArrayDeque<T>(8); 207 this.hasExpandedLeft = new BitSet(); 208 stack.addLast(root); 209 } 210 211 @Override 212 protected T computeNext() { 213 while (!stack.isEmpty()) { 214 T node = stack.getLast(); 215 if (hasExpandedLeft.get(stack.size() - 1)) { 216 stack.removeLast(); 217 hasExpandedLeft.clear(stack.size()); 218 pushIfPresent(stack, rightChild(node)); 219 return node; 220 } else { 221 hasExpandedLeft.set(stack.size() - 1); 222 pushIfPresent(stack, leftChild(node)); 223 } 224 } 225 return endOfData(); 226 } 227 } 228 229 private static <T> void pushIfPresent(Deque<T> stack, Optional<T> node) { 230 if (node.isPresent()) { 231 stack.addLast(node.get()); 232 } 233 } 234 235 private static <T> void acceptIfPresent(Consumer<? super T> action, Optional<T> node) { 236 if (node.isPresent()) { 237 action.accept(node.get()); 238 } 239 } 240}