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; 028 029/** 030 * A variant of {@link TreeTraverser} for binary trees, providing additional traversals specific to 031 * binary trees. 032 * 033 * @author Louis Wasserman 034 * @since 15.0 035 * @deprecated Use {@link com.google.common.graph.Traverser} instead. All instance methods except 036 * for {@link #inOrderTraversal} have their equivalent on the result of {@code 037 * Traverser.forTree(tree)} where {@code tree} implements {@code SuccessorsFunction}, which has 038 * a similar API as {@link #children}. 039 * <p>This class is scheduled to be removed in January 2018. 040 */ 041@Deprecated 042@Beta 043@GwtCompatible 044public abstract class BinaryTreeTraverser<T> extends TreeTraverser<T> { 045 046 /** 047 * Returns the left child of the specified node, or {@link Optional#absent()} if the specified 048 * node has no left child. 049 */ 050 public abstract Optional<T> leftChild(T root); 051 052 /** 053 * Returns the right child of the specified node, or {@link Optional#absent()} if the specified 054 * node has no right child. 055 */ 056 public abstract Optional<T> rightChild(T root); 057 058 /** 059 * Returns the children of this node, in left-to-right order. 060 */ 061 @Override 062 public final Iterable<T> children(final T root) { 063 checkNotNull(root); 064 return new FluentIterable<T>() { 065 @Override 066 public Iterator<T> iterator() { 067 return new AbstractIterator<T>() { 068 boolean doneLeft; 069 boolean doneRight; 070 071 @Override 072 protected T computeNext() { 073 if (!doneLeft) { 074 doneLeft = true; 075 Optional<T> left = leftChild(root); 076 if (left.isPresent()) { 077 return left.get(); 078 } 079 } 080 if (!doneRight) { 081 doneRight = true; 082 Optional<T> right = rightChild(root); 083 if (right.isPresent()) { 084 return right.get(); 085 } 086 } 087 return endOfData(); 088 } 089 }; 090 } 091 }; 092 } 093 094 @Override 095 UnmodifiableIterator<T> preOrderIterator(T root) { 096 return new PreOrderIterator(root); 097 } 098 099 /* 100 * Optimized implementation of preOrderIterator for binary trees. 101 */ 102 private final class PreOrderIterator extends UnmodifiableIterator<T> 103 implements PeekingIterator<T> { 104 private final Deque<T> stack; 105 106 PreOrderIterator(T root) { 107 this.stack = new ArrayDeque<T>(8); 108 stack.addLast(root); 109 } 110 111 @Override 112 public boolean hasNext() { 113 return !stack.isEmpty(); 114 } 115 116 @Override 117 public T next() { 118 T result = stack.removeLast(); 119 pushIfPresent(stack, rightChild(result)); 120 pushIfPresent(stack, leftChild(result)); 121 return result; 122 } 123 124 @Override 125 public T peek() { 126 return stack.getLast(); 127 } 128 } 129 130 @Override 131 UnmodifiableIterator<T> postOrderIterator(T root) { 132 return new PostOrderIterator(root); 133 } 134 135 /* 136 * Optimized implementation of postOrderIterator for binary trees. 137 */ 138 private final class PostOrderIterator extends UnmodifiableIterator<T> { 139 private final Deque<T> stack; 140 private final BitSet hasExpanded; 141 142 PostOrderIterator(T root) { 143 this.stack = new ArrayDeque<T>(8); 144 stack.addLast(root); 145 this.hasExpanded = new BitSet(); 146 } 147 148 @Override 149 public boolean hasNext() { 150 return !stack.isEmpty(); 151 } 152 153 @Override 154 public T next() { 155 while (true) { 156 T node = stack.getLast(); 157 boolean expandedNode = hasExpanded.get(stack.size() - 1); 158 if (expandedNode) { 159 stack.removeLast(); 160 hasExpanded.clear(stack.size()); 161 return node; 162 } else { 163 hasExpanded.set(stack.size() - 1); 164 pushIfPresent(stack, rightChild(node)); 165 pushIfPresent(stack, leftChild(node)); 166 } 167 } 168 } 169 } 170 171 // TODO(lowasser): see if any significant optimizations are possible for breadthFirstIterator 172 173 public final FluentIterable<T> inOrderTraversal(final T root) { 174 checkNotNull(root); 175 return new FluentIterable<T>() { 176 @Override 177 public UnmodifiableIterator<T> iterator() { 178 return new InOrderIterator(root); 179 } 180 }; 181 } 182 183 private final class InOrderIterator extends AbstractIterator<T> { 184 private final Deque<T> stack; 185 private final BitSet hasExpandedLeft; 186 187 InOrderIterator(T root) { 188 this.stack = new ArrayDeque<T>(8); 189 this.hasExpandedLeft = new BitSet(); 190 stack.addLast(root); 191 } 192 193 @Override 194 protected T computeNext() { 195 while (!stack.isEmpty()) { 196 T node = stack.getLast(); 197 if (hasExpandedLeft.get(stack.size() - 1)) { 198 stack.removeLast(); 199 hasExpandedLeft.clear(stack.size()); 200 pushIfPresent(stack, rightChild(node)); 201 return node; 202 } else { 203 hasExpandedLeft.set(stack.size() - 1); 204 pushIfPresent(stack, leftChild(node)); 205 } 206 } 207 return endOfData(); 208 } 209 } 210 211 private static <T> void pushIfPresent(Deque<T> stack, Optional<T> node) { 212 if (node.isPresent()) { 213 stack.addLast(node.get()); 214 } 215 } 216}