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