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; 024 025import java.util.BitSet; 026import java.util.Iterator; 027import java.util.LinkedList; 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 */ 036@Beta 037@GwtCompatible(emulated = true) 038public abstract class BinaryTreeTraverser<T> extends TreeTraverser<T> { 039 // TODO(user): make this GWT-compatible when we've checked in LinkedList and BitSet emulation 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 } 088 089 @Override 090 UnmodifiableIterator<T> preOrderIterator(T root) { 091 return new PreOrderIterator(root); 092 } 093 094 /* 095 * Optimized implementation of preOrderIterator for binary trees. 096 */ 097 private final class PreOrderIterator extends UnmodifiableIterator<T> 098 implements PeekingIterator<T> { 099 private final LinkedList<T> stack; 100 101 PreOrderIterator(T root) { 102 this.stack = new LinkedList<T>(); 103 stack.addLast(root); 104 } 105 106 @Override 107 public boolean hasNext() { 108 return !stack.isEmpty(); 109 } 110 111 @Override 112 public T next() { 113 T result = stack.removeLast(); 114 pushIfPresent(stack, rightChild(result)); 115 pushIfPresent(stack, leftChild(result)); 116 return result; 117 } 118 119 @Override 120 public T peek() { 121 return stack.getLast(); 122 } 123 } 124 125 @Override 126 UnmodifiableIterator<T> postOrderIterator(T root) { 127 return new PostOrderIterator(root); 128 } 129 130 /* 131 * Optimized implementation of postOrderIterator for binary trees. 132 */ 133 private final class PostOrderIterator extends UnmodifiableIterator<T> { 134 private final LinkedList<T> stack; 135 private final BitSet hasExpanded; 136 137 PostOrderIterator(T root) { 138 this.stack = new LinkedList<T>(); 139 stack.addLast(root); 140 this.hasExpanded = new BitSet(); 141 } 142 143 @Override 144 public boolean hasNext() { 145 return !stack.isEmpty(); 146 } 147 148 @Override 149 public T next() { 150 while (true) { 151 T node = stack.getLast(); 152 boolean expandedNode = hasExpanded.get(stack.size() - 1); 153 if (expandedNode) { 154 stack.removeLast(); 155 hasExpanded.clear(stack.size()); 156 return node; 157 } else { 158 hasExpanded.set(stack.size() - 1); 159 pushIfPresent(stack, rightChild(node)); 160 pushIfPresent(stack, leftChild(node)); 161 } 162 } 163 } 164 } 165 166 // TODO(user): see if any significant optimizations are possible for breadthFirstIterator 167 168 public final FluentIterable<T> inOrderTraversal(final T root) { 169 checkNotNull(root); 170 return new FluentIterable<T>() { 171 @Override 172 public UnmodifiableIterator<T> iterator() { 173 return new InOrderIterator(root); 174 } 175 }; 176 } 177 178 private final class InOrderIterator extends AbstractIterator<T> { 179 private final LinkedList<T> stack; 180 private final BitSet hasExpandedLeft; 181 182 InOrderIterator(T root) { 183 this.stack = new LinkedList<T>(); 184 this.hasExpandedLeft = new BitSet(); 185 stack.addLast(root); 186 } 187 188 @Override 189 protected T computeNext() { 190 while (!stack.isEmpty()) { 191 T node = stack.getLast(); 192 if (hasExpandedLeft.get(stack.size() - 1)) { 193 stack.removeLast(); 194 hasExpandedLeft.clear(stack.size()); 195 pushIfPresent(stack, rightChild(node)); 196 return node; 197 } else { 198 hasExpandedLeft.set(stack.size() - 1); 199 pushIfPresent(stack, leftChild(node)); 200 } 201 } 202 return endOfData(); 203 } 204 } 205 206 private static <T> void pushIfPresent(LinkedList<T> stack, Optional<T> node) { 207 if (node.isPresent()) { 208 stack.addLast(node.get()); 209 } 210 } 211}