com.google.common.collect.BinaryTreeTraverser Maven / Gradle / Ivy
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Optional;
import java.util.ArrayDeque;
import java.util.BitSet;
import java.util.Deque;
import java.util.Iterator;
/**
* A variant of {@link TreeTraverser} for binary trees, providing additional traversals specific to
* binary trees.
*
* @author Louis Wasserman
* @since 15.0
*/
@Beta
@GwtCompatible(emulated = true)
public abstract class BinaryTreeTraverser extends TreeTraverser {
// TODO(user): make this GWT-compatible when we've checked in ArrayDeque and BitSet emulation
/**
* Returns the left child of the specified node, or {@link Optional#absent()} if the specified
* node has no left child.
*/
public abstract Optional leftChild(T root);
/**
* Returns the right child of the specified node, or {@link Optional#absent()} if the specified
* node has no right child.
*/
public abstract Optional rightChild(T root);
/**
* Returns the children of this node, in left-to-right order.
*/
@Override
public final Iterable children(final T root) {
checkNotNull(root);
return new FluentIterable() {
@Override
public Iterator iterator() {
return new AbstractIterator() {
boolean doneLeft;
boolean doneRight;
@Override
protected T computeNext() {
if (!doneLeft) {
doneLeft = true;
Optional left = leftChild(root);
if (left.isPresent()) {
return left.get();
}
}
if (!doneRight) {
doneRight = true;
Optional right = rightChild(root);
if (right.isPresent()) {
return right.get();
}
}
return endOfData();
}
};
}
};
}
@Override
UnmodifiableIterator preOrderIterator(T root) {
return new PreOrderIterator(root);
}
/*
* Optimized implementation of preOrderIterator for binary trees.
*/
private final class PreOrderIterator extends UnmodifiableIterator
implements PeekingIterator {
private final Deque stack;
PreOrderIterator(T root) {
this.stack = new ArrayDeque();
stack.addLast(root);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public T next() {
T result = stack.removeLast();
pushIfPresent(stack, rightChild(result));
pushIfPresent(stack, leftChild(result));
return result;
}
@Override
public T peek() {
return stack.getLast();
}
}
@Override
UnmodifiableIterator postOrderIterator(T root) {
return new PostOrderIterator(root);
}
/*
* Optimized implementation of postOrderIterator for binary trees.
*/
private final class PostOrderIterator extends UnmodifiableIterator {
private final Deque stack;
private final BitSet hasExpanded;
PostOrderIterator(T root) {
this.stack = new ArrayDeque();
stack.addLast(root);
this.hasExpanded = new BitSet();
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public T next() {
while (true) {
T node = stack.getLast();
boolean expandedNode = hasExpanded.get(stack.size() - 1);
if (expandedNode) {
stack.removeLast();
hasExpanded.clear(stack.size());
return node;
} else {
hasExpanded.set(stack.size() - 1);
pushIfPresent(stack, rightChild(node));
pushIfPresent(stack, leftChild(node));
}
}
}
}
// TODO(user): see if any significant optimizations are possible for breadthFirstIterator
public final FluentIterable inOrderTraversal(final T root) {
checkNotNull(root);
return new FluentIterable() {
@Override
public UnmodifiableIterator iterator() {
return new InOrderIterator(root);
}
};
}
private final class InOrderIterator extends AbstractIterator {
private final Deque stack;
private final BitSet hasExpandedLeft;
InOrderIterator(T root) {
this.stack = new ArrayDeque();
this.hasExpandedLeft = new BitSet();
stack.addLast(root);
}
@Override
protected T computeNext() {
while (!stack.isEmpty()) {
T node = stack.getLast();
if (hasExpandedLeft.get(stack.size() - 1)) {
stack.removeLast();
hasExpandedLeft.clear(stack.size());
pushIfPresent(stack, rightChild(node));
return node;
} else {
hasExpandedLeft.set(stack.size() - 1);
pushIfPresent(stack, leftChild(node));
}
}
return endOfData();
}
}
private static void pushIfPresent(Deque stack, Optional node) {
if (node.isPresent()) {
stack.addLast(node.get());
}
}
}