001/* 002 * Copyright (C) 2017 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.graph; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021import static com.google.common.collect.Iterators.singletonIterator; 022 023import com.google.common.annotations.Beta; 024import com.google.common.collect.AbstractIterator; 025import com.google.common.collect.Iterables; 026import com.google.common.collect.UnmodifiableIterator; 027import java.util.ArrayDeque; 028import java.util.Deque; 029import java.util.HashSet; 030import java.util.Iterator; 031import java.util.Queue; 032import java.util.Set; 033 034/** 035 * Provides methods for traversing a graph. 036 * 037 * @author Jens Nyman 038 * @param <N> Node parameter type 039 * @since 23.1 040 */ 041@Beta 042public abstract class Traverser<N> { 043 044 /** 045 * Creates a new traverser for the given general {@code graph}. 046 * 047 * <p>If {@code graph} is known to be tree-shaped, consider using {@link 048 * #forTree(SuccessorsFunction)} instead. 049 * 050 * <p><b>Performance notes</b> 051 * 052 * <ul> 053 * <li>Traversals require <i>O(n)</i> time (where <i>n</i> is the number of nodes reachable from 054 * the start node), assuming that the node objects have <i>O(1)</i> {@code equals()} and 055 * {@code hashCode()} implementations. 056 * <li>While traversing, the traverser will use <i>O(n)</i> space (where <i>n</i> is the number 057 * of nodes that have thus far been visited), plus <i>O(H)</i> space (where <i>H</i> is the 058 * number of nodes that have been seen but not yet visited, that is, the "horizon"). 059 * </ul> 060 * 061 * @param graph {@link SuccessorsFunction} representing a general graph that may have cycles. 062 */ 063 public static <N> Traverser<N> forGraph(SuccessorsFunction<N> graph) { 064 checkNotNull(graph); 065 return new GraphTraverser<>(graph); 066 } 067 068 /** 069 * Creates a new traverser for a directed acyclic graph that has at most one path from the start 070 * node to any node reachable from the start node, such as a tree. 071 * 072 * <p>Providing graphs that don't conform to the above description may lead to: 073 * 074 * <ul> 075 * <li>Traversal not terminating (if the graph has cycles) 076 * <li>Nodes being visited multiple times (if multiple paths exist from the start node to any 077 * node reachable from it) 078 * </ul> 079 * 080 * In these cases, use {@link #forGraph(SuccessorsFunction)} instead. 081 * 082 * <p><b>Performance notes</b> 083 * 084 * <ul> 085 * <li>Traversals require <i>O(n)</i> time (where <i>n</i> is the number of nodes reachable from 086 * the start node). 087 * <li>While traversing, the traverser will use <i>O(H)</i> space (where <i>H</i> is the number 088 * of nodes that have been seen but not yet visited, that is, the "horizon"). 089 * </ul> 090 * 091 * <p><b>Examples</b> 092 * 093 * <p>This is a valid input graph (all edges are directed facing downwards): 094 * 095 * <pre>{@code 096 * a b c 097 * / \ / \ | 098 * / \ / \ | 099 * d e f g 100 * | 101 * | 102 * h 103 * }</pre> 104 * 105 * <p>This is <b>not</b> a valid input graph (all edges are directed facing downwards): 106 * 107 * <pre>{@code 108 * a b 109 * / \ / \ 110 * / \ / \ 111 * c d e 112 * \ / 113 * \ / 114 * f 115 * }</pre> 116 * 117 * <p>because there are two paths from {@code b} to {@code f} ({@code b->d->f} and {@code 118 * b->e->f}). 119 * 120 * <p><b>Note on binary trees</b> 121 * 122 * <p>This method can be used to traverse over a binary tree. Given methods {@code 123 * leftChild(node)} and {@code rightChild(node)}, this method can be called as 124 * 125 * <pre>{@code 126 * Traverser.forTree(node -> ImmutableList.of(leftChild(node), rightChild(node))); 127 * }</pre> 128 * 129 * @param tree {@link SuccessorsFunction} representing a directed acyclic graph that has at most 130 * one path between any two nodes 131 */ 132 public static <N> Traverser<N> forTree(SuccessorsFunction<N> tree) { 133 checkNotNull(tree); 134 if (tree instanceof BaseGraph) { 135 checkArgument(((BaseGraph<?>) tree).isDirected(), "Undirected graphs can never be trees."); 136 } 137 if (tree instanceof Network) { 138 checkArgument(((Network<?, ?>) tree).isDirected(), "Undirected networks can never be trees."); 139 } 140 return new TreeTraverser<>(tree); 141 } 142 143 /** 144 * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in 145 * the order of a breadth-first traversal. That is, all the nodes of depth 0 are returned, then 146 * depth 1, then 2, and so on. 147 * 148 * <p><b>Example:</b> The following graph with {@code startNode} {@code a} would return nodes in 149 * the order {@code abcdef} (assuming successors are returned in alphabetical order). 150 * 151 * <pre>{@code 152 * b ---- a ---- d 153 * | | 154 * | | 155 * e ---- c ---- f 156 * }</pre> 157 * 158 * <p>The behavior of this method is undefined if the nodes, or the topology of the graph, change 159 * while iteration is in progress. 160 * 161 * <p>The returned {@code Iterable} can be iterated over multiple times. Every iterator will 162 * compute its next element on the fly. It is thus possible to limit the traversal to a certain 163 * number of nodes as follows: 164 * 165 * <pre>{@code 166 * Iterables.limit(Traverser.forGraph(graph).breadthFirst(node), maxNumberOfNodes); 167 * }</pre> 168 * 169 * <p>See <a href="https://en.wikipedia.org/wiki/Breadth-first_search">Wikipedia</a> for more 170 * info. 171 * 172 * @throws IllegalArgumentException if {@code startNode} is not an element of the graph 173 */ 174 public abstract Iterable<N> breadthFirst(N startNode); 175 176 /** 177 * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in 178 * the order of a depth-first pre-order traversal. "Pre-order" implies that nodes appear in the 179 * {@code Iterable} in the order in which they are first visited. 180 * 181 * <p><b>Example:</b> The following graph with {@code startNode} {@code a} would return nodes in 182 * the order {@code abecfd} (assuming successors are returned in alphabetical order). 183 * 184 * <pre>{@code 185 * b ---- a ---- d 186 * | | 187 * | | 188 * e ---- c ---- f 189 * }</pre> 190 * 191 * <p>The behavior of this method is undefined if the nodes, or the topology of the graph, change 192 * while iteration is in progress. 193 * 194 * <p>The returned {@code Iterable} can be iterated over multiple times. Every iterator will 195 * compute its next element on the fly. It is thus possible to limit the traversal to a certain 196 * number of nodes as follows: 197 * 198 * <pre>{@code 199 * Iterables.limit( 200 * Traverser.forGraph(graph).depthFirstPreOrder(node), maxNumberOfNodes); 201 * }</pre> 202 * 203 * <p>See <a href="https://en.wikipedia.org/wiki/Depth-first_search">Wikipedia</a> for more info. 204 * 205 * @throws IllegalArgumentException if {@code startNode} is not an element of the graph 206 */ 207 public abstract Iterable<N> depthFirstPreOrder(N startNode); 208 209 /** 210 * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in 211 * the order of a depth-first post-order traversal. "Post-order" implies that nodes appear in the 212 * {@code Iterable} in the order in which they are visited for the last time. 213 * 214 * <p><b>Example:</b> The following graph with {@code startNode} {@code a} would return nodes in 215 * the order {@code fcebda} (assuming successors are returned in alphabetical order). 216 * 217 * <pre>{@code 218 * b ---- a ---- d 219 * | | 220 * | | 221 * e ---- c ---- f 222 * }</pre> 223 * 224 * <p>The behavior of this method is undefined if the nodes, or the topology of the graph, change 225 * while iteration is in progress. 226 * 227 * <p>The returned {@code Iterable} can be iterated over multiple times. Every iterator will 228 * compute its next element on the fly. It is thus possible to limit the traversal to a certain 229 * number of nodes as follows: 230 * 231 * <pre>{@code 232 * Iterables.limit( 233 * Traverser.forGraph(graph).depthFirstPostOrder(node), maxNumberOfNodes); 234 * }</pre> 235 * 236 * <p>See <a href="https://en.wikipedia.org/wiki/Depth-first_search">Wikipedia</a> for more info. 237 * 238 * @throws IllegalArgumentException if {@code startNode} is not an element of the graph 239 */ 240 public abstract Iterable<N> depthFirstPostOrder(N startNode); 241 242 // Avoid subclasses outside of this class 243 private Traverser() {} 244 245 private static final class GraphTraverser<N> extends Traverser<N> { 246 private final SuccessorsFunction<N> graph; 247 248 GraphTraverser(SuccessorsFunction<N> graph) { 249 this.graph = checkNotNull(graph); 250 } 251 252 @Override 253 public Iterable<N> breadthFirst(final N startNode) { 254 checkNotNull(startNode); 255 checkThatNodeIsInGraph(startNode); 256 return new Iterable<N>() { 257 @Override 258 public Iterator<N> iterator() { 259 return new BreadthFirstIterator(startNode); 260 } 261 }; 262 } 263 264 @Override 265 public Iterable<N> depthFirstPreOrder(final N startNode) { 266 checkNotNull(startNode); 267 checkThatNodeIsInGraph(startNode); 268 return new Iterable<N>() { 269 @Override 270 public Iterator<N> iterator() { 271 return new DepthFirstIterator(startNode, Order.PREORDER); 272 } 273 }; 274 } 275 276 @Override 277 public Iterable<N> depthFirstPostOrder(final N startNode) { 278 checkNotNull(startNode); 279 checkThatNodeIsInGraph(startNode); 280 return new Iterable<N>() { 281 @Override 282 public Iterator<N> iterator() { 283 return new DepthFirstIterator(startNode, Order.POSTORDER); 284 } 285 }; 286 } 287 288 @SuppressWarnings("CheckReturnValue") 289 private void checkThatNodeIsInGraph(N startNode) { 290 // successors() throws an IllegalArgumentException for nodes that are not an element of the 291 // graph. 292 graph.successors(startNode); 293 } 294 295 private final class BreadthFirstIterator extends UnmodifiableIterator<N> { 296 private final Queue<N> queue = new ArrayDeque<>(); 297 private final Set<N> visited = new HashSet<>(); 298 299 BreadthFirstIterator(N root) { 300 queue.add(root); 301 visited.add(root); 302 } 303 304 @Override 305 public boolean hasNext() { 306 return !queue.isEmpty(); 307 } 308 309 @Override 310 public N next() { 311 N current = queue.remove(); 312 for (N neighbor : graph.successors(current)) { 313 if (visited.add(neighbor)) { 314 queue.add(neighbor); 315 } 316 } 317 return current; 318 } 319 } 320 321 private final class DepthFirstIterator extends AbstractIterator<N> { 322 private final Deque<NodeAndSuccessors> stack = new ArrayDeque<>(); 323 private final Set<N> visited = new HashSet<>(); 324 private final Order order; 325 326 DepthFirstIterator(N root, Order order) { 327 // our invariant is that in computeNext we call next on the iterator at the top first, so we 328 // need to start with one additional item on that iterator 329 stack.push(withSuccessors(root)); 330 this.order = order; 331 } 332 333 @Override 334 protected N computeNext() { 335 while (true) { 336 if (stack.isEmpty()) { 337 return endOfData(); 338 } 339 NodeAndSuccessors node = stack.getFirst(); 340 boolean firstVisit = visited.add(node.node); 341 boolean lastVisit = !node.successorIterator.hasNext(); 342 boolean produceNode = 343 (firstVisit && order == Order.PREORDER) || (lastVisit && order == Order.POSTORDER); 344 if (lastVisit) { 345 stack.pop(); 346 } else { 347 // we need to push a neighbor, but only if we haven't already seen it 348 N successor = node.successorIterator.next(); 349 if (!visited.contains(successor)) { 350 stack.push(withSuccessors(successor)); 351 } 352 } 353 if (produceNode) { 354 return node.node; 355 } 356 } 357 } 358 359 NodeAndSuccessors withSuccessors(N node) { 360 return new NodeAndSuccessors(node, graph.successors(node)); 361 } 362 363 /** A simple tuple of a node and a partially iterated {@link Iterator} of its successors. */ 364 private final class NodeAndSuccessors { 365 final N node; 366 final Iterator<? extends N> successorIterator; 367 368 NodeAndSuccessors(N node, Iterable<? extends N> successors) { 369 this.node = node; 370 this.successorIterator = successors.iterator(); 371 } 372 } 373 } 374 } 375 376 private static final class TreeTraverser<N> extends Traverser<N> { 377 private final SuccessorsFunction<N> tree; 378 379 TreeTraverser(SuccessorsFunction<N> tree) { 380 this.tree = checkNotNull(tree); 381 } 382 383 @Override 384 public Iterable<N> breadthFirst(final N startNode) { 385 checkNotNull(startNode); 386 checkThatNodeIsInTree(startNode); 387 return new Iterable<N>() { 388 @Override 389 public Iterator<N> iterator() { 390 return new BreadthFirstIterator(startNode); 391 } 392 }; 393 } 394 395 @Override 396 public Iterable<N> depthFirstPreOrder(final N startNode) { 397 checkNotNull(startNode); 398 checkThatNodeIsInTree(startNode); 399 return new Iterable<N>() { 400 @Override 401 public Iterator<N> iterator() { 402 return new DepthFirstPreOrderIterator(startNode); 403 } 404 }; 405 } 406 407 @Override 408 public Iterable<N> depthFirstPostOrder(final N startNode) { 409 checkNotNull(startNode); 410 checkThatNodeIsInTree(startNode); 411 return new Iterable<N>() { 412 @Override 413 public Iterator<N> iterator() { 414 return new DepthFirstPostOrderIterator(startNode); 415 } 416 }; 417 } 418 419 @SuppressWarnings("CheckReturnValue") 420 private void checkThatNodeIsInTree(N startNode) { 421 // successors() throws an IllegalArgumentException for nodes that are not an element of the 422 // graph. 423 tree.successors(startNode); 424 } 425 426 private final class BreadthFirstIterator extends UnmodifiableIterator<N> { 427 private final Queue<N> queue = new ArrayDeque<>(); 428 429 BreadthFirstIterator(N root) { 430 queue.add(root); 431 } 432 433 @Override 434 public boolean hasNext() { 435 return !queue.isEmpty(); 436 } 437 438 @Override 439 public N next() { 440 N current = queue.remove(); 441 Iterables.addAll(queue, tree.successors(current)); 442 return current; 443 } 444 } 445 446 private final class DepthFirstPreOrderIterator extends UnmodifiableIterator<N> { 447 private final Deque<Iterator<? extends N>> stack = new ArrayDeque<>(); 448 449 DepthFirstPreOrderIterator(N root) { 450 stack.addLast(singletonIterator(checkNotNull(root))); 451 } 452 453 @Override 454 public boolean hasNext() { 455 return !stack.isEmpty(); 456 } 457 458 @Override 459 public N next() { 460 Iterator<? extends N> iterator = stack.getLast(); // throws NoSuchElementException if empty 461 N result = checkNotNull(iterator.next()); 462 if (!iterator.hasNext()) { 463 stack.removeLast(); 464 } 465 Iterator<? extends N> childIterator = tree.successors(result).iterator(); 466 if (childIterator.hasNext()) { 467 stack.addLast(childIterator); 468 } 469 return result; 470 } 471 } 472 473 private final class DepthFirstPostOrderIterator extends AbstractIterator<N> { 474 private final ArrayDeque<NodeAndChildren> stack = new ArrayDeque<>(); 475 476 DepthFirstPostOrderIterator(N root) { 477 stack.addLast(withChildren(root)); 478 } 479 480 @Override 481 protected N computeNext() { 482 while (!stack.isEmpty()) { 483 NodeAndChildren top = stack.getLast(); 484 if (top.childIterator.hasNext()) { 485 N child = top.childIterator.next(); 486 stack.addLast(withChildren(child)); 487 } else { 488 stack.removeLast(); 489 return top.node; 490 } 491 } 492 return endOfData(); 493 } 494 495 NodeAndChildren withChildren(N node) { 496 return new NodeAndChildren(node, tree.successors(node)); 497 } 498 499 /** A simple tuple of a node and a partially iterated {@link Iterator} of its children. */ 500 private final class NodeAndChildren { 501 final N node; 502 final Iterator<? extends N> childIterator; 503 504 NodeAndChildren(N node, Iterable<? extends N> children) { 505 this.node = node; 506 this.childIterator = children.iterator(); 507 } 508 } 509 } 510 } 511 512 private enum Order { 513 PREORDER, 514 POSTORDER 515 } 516}