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