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}