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}