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 /** 060 * Returns the children of this node, in left-to-right order. 061 */ 062 @Override 063 public final Iterable<T> children(final T root) { 064 checkNotNull(root); 065 return new FluentIterable<T>() { 066 @Override 067 public Iterator<T> iterator() { 068 return new AbstractIterator<T>() { 069 boolean doneLeft; 070 boolean doneRight; 071 072 @Override 073 protected T computeNext() { 074 if (!doneLeft) { 075 doneLeft = true; 076 Optional<T> left = leftChild(root); 077 if (left.isPresent()) { 078 return left.get(); 079 } 080 } 081 if (!doneRight) { 082 doneRight = true; 083 Optional<T> right = rightChild(root); 084 if (right.isPresent()) { 085 return right.get(); 086 } 087 } 088 return endOfData(); 089 } 090 }; 091 } 092 093 @Override 094 public void forEach(Consumer<? super T> action) { 095 acceptIfPresent(action, leftChild(root)); 096 acceptIfPresent(action, rightChild(root)); 097 } 098 }; 099 } 100 101 @Override 102 UnmodifiableIterator<T> preOrderIterator(T root) { 103 return new PreOrderIterator(root); 104 } 105 106 /* 107 * Optimized implementation of preOrderIterator for binary trees. 108 */ 109 private final class PreOrderIterator extends UnmodifiableIterator<T> 110 implements PeekingIterator<T> { 111 private final Deque<T> stack; 112 113 PreOrderIterator(T root) { 114 this.stack = new ArrayDeque<T>(8); 115 stack.addLast(root); 116 } 117 118 @Override 119 public boolean hasNext() { 120 return !stack.isEmpty(); 121 } 122 123 @Override 124 public T next() { 125 T result = stack.removeLast(); 126 pushIfPresent(stack, rightChild(result)); 127 pushIfPresent(stack, leftChild(result)); 128 return result; 129 } 130 131 @Override 132 public T peek() { 133 return stack.getLast(); 134 } 135 } 136 137 @Override 138 UnmodifiableIterator<T> postOrderIterator(T root) { 139 return new PostOrderIterator(root); 140 } 141 142 /* 143 * Optimized implementation of postOrderIterator for binary trees. 144 */ 145 private final class PostOrderIterator extends UnmodifiableIterator<T> { 146 private final Deque<T> stack; 147 private final BitSet hasExpanded; 148 149 PostOrderIterator(T root) { 150 this.stack = new ArrayDeque<T>(8); 151 stack.addLast(root); 152 this.hasExpanded = new BitSet(); 153 } 154 155 @Override 156 public boolean hasNext() { 157 return !stack.isEmpty(); 158 } 159 160 @Override 161 public T next() { 162 while (true) { 163 T node = stack.getLast(); 164 boolean expandedNode = hasExpanded.get(stack.size() - 1); 165 if (expandedNode) { 166 stack.removeLast(); 167 hasExpanded.clear(stack.size()); 168 return node; 169 } else { 170 hasExpanded.set(stack.size() - 1); 171 pushIfPresent(stack, rightChild(node)); 172 pushIfPresent(stack, leftChild(node)); 173 } 174 } 175 } 176 } 177 178 // TODO(lowasser): see if any significant optimizations are possible for breadthFirstIterator 179 180 public final FluentIterable<T> inOrderTraversal(final T root) { 181 checkNotNull(root); 182 return new FluentIterable<T>() { 183 @Override 184 public UnmodifiableIterator<T> iterator() { 185 return new InOrderIterator(root); 186 } 187 188 @Override 189 public void forEach(Consumer<? super T> action) { 190 checkNotNull(action); 191 new Consumer<T>() { 192 @Override 193 public void accept(T t) { 194 acceptIfPresent(this, leftChild(t)); 195 action.accept(t); 196 acceptIfPresent(this, rightChild(t)); 197 } 198 }.accept(root); 199 } 200 }; 201 } 202 203 private final class InOrderIterator extends AbstractIterator<T> { 204 private final Deque<T> stack; 205 private final BitSet hasExpandedLeft; 206 207 InOrderIterator(T root) { 208 this.stack = new ArrayDeque<T>(8); 209 this.hasExpandedLeft = new BitSet(); 210 stack.addLast(root); 211 } 212 213 @Override 214 protected T computeNext() { 215 while (!stack.isEmpty()) { 216 T node = stack.getLast(); 217 if (hasExpandedLeft.get(stack.size() - 1)) { 218 stack.removeLast(); 219 hasExpandedLeft.clear(stack.size()); 220 pushIfPresent(stack, rightChild(node)); 221 return node; 222 } else { 223 hasExpandedLeft.set(stack.size() - 1); 224 pushIfPresent(stack, leftChild(node)); 225 } 226 } 227 return endOfData(); 228 } 229 } 230 231 private static <T> void pushIfPresent(Deque<T> stack, Optional<T> node) { 232 if (node.isPresent()) { 233 stack.addLast(node.get()); 234 } 235 } 236 237 private static <T> void acceptIfPresent(Consumer<? super T> action, Optional<T> node) { 238 if (node.isPresent()) { 239 action.accept(node.get()); 240 } 241 } 242}