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 private static final class GraphTraverser<N> extends Traverser<N> { 243 private final SuccessorsFunction<N> graph; 244 245 GraphTraverser(SuccessorsFunction<N> graph) { 246 this.graph = checkNotNull(graph); 247 } 248 249 @Override 250 public Iterable<N> breadthFirst(final N startNode) { 251 checkNotNull(startNode); 252 checkThatNodeIsInGraph(startNode); 253 return new Iterable<N>() { 254 @Override 255 public Iterator<N> iterator() { 256 return new BreadthFirstIterator(startNode); 257 } 258 }; 259 } 260 261 @Override 262 public Iterable<N> depthFirstPreOrder(final N startNode) { 263 checkNotNull(startNode); 264 checkThatNodeIsInGraph(startNode); 265 return new Iterable<N>() { 266 @Override 267 public Iterator<N> iterator() { 268 return new DepthFirstIterator(startNode, Order.PREORDER); 269 } 270 }; 271 } 272 273 @Override 274 public Iterable<N> depthFirstPostOrder(final N startNode) { 275 checkNotNull(startNode); 276 checkThatNodeIsInGraph(startNode); 277 return new Iterable<N>() { 278 @Override 279 public Iterator<N> iterator() { 280 return new DepthFirstIterator(startNode, Order.POSTORDER); 281 } 282 }; 283 } 284 285 @SuppressWarnings("CheckReturnValue") 286 private void checkThatNodeIsInGraph(N startNode) { 287 // successors() throws an IllegalArgumentException for nodes that are not an element of the 288 // graph. 289 graph.successors(startNode); 290 } 291 292 private final class BreadthFirstIterator extends UnmodifiableIterator<N> { 293 private final Queue<N> queue = new ArrayDeque<>(); 294 private final Set<N> visited = new HashSet<>(); 295 296 BreadthFirstIterator(N root) { 297 queue.add(root); 298 visited.add(root); 299 } 300 301 @Override 302 public boolean hasNext() { 303 return !queue.isEmpty(); 304 } 305 306 @Override 307 public N next() { 308 N current = queue.remove(); 309 for (N neighbor : graph.successors(current)) { 310 if (visited.add(neighbor)) { 311 queue.add(neighbor); 312 } 313 } 314 return current; 315 } 316 } 317 318 private final class DepthFirstIterator extends AbstractIterator<N> { 319 private final Deque<NodeAndSuccessors> stack = new ArrayDeque<>(); 320 private final Set<N> visited = new HashSet<>(); 321 private final Order order; 322 323 DepthFirstIterator(N root, Order order) { 324 // our invariant is that in computeNext we call next on the iterator at the top first, so we 325 // need to start with one additional item on that iterator 326 stack.push(withSuccessors(root)); 327 this.order = order; 328 } 329 330 @Override 331 protected N computeNext() { 332 while (true) { 333 if (stack.isEmpty()) { 334 return endOfData(); 335 } 336 NodeAndSuccessors node = stack.getFirst(); 337 boolean firstVisit = visited.add(node.node); 338 boolean lastVisit = !node.successorIterator.hasNext(); 339 boolean produceNode = 340 (firstVisit && order == Order.PREORDER) || (lastVisit && order == Order.POSTORDER); 341 if (lastVisit) { 342 stack.pop(); 343 } else { 344 // we need to push a neighbor, but only if we haven't already seen it 345 N successor = node.successorIterator.next(); 346 if (!visited.contains(successor)) { 347 stack.push(withSuccessors(successor)); 348 } 349 } 350 if (produceNode) { 351 return node.node; 352 } 353 } 354 } 355 356 NodeAndSuccessors withSuccessors(N node) { 357 return new NodeAndSuccessors(node, graph.successors(node)); 358 } 359 360 /** A simple tuple of a node and a partially iterated {@link Iterator} of its successors. */ 361 private final class NodeAndSuccessors { 362 final N node; 363 final Iterator<? extends N> successorIterator; 364 365 NodeAndSuccessors(N node, Iterable<? extends N> successors) { 366 this.node = node; 367 this.successorIterator = successors.iterator(); 368 } 369 } 370 } 371 } 372 373 private static final class TreeTraverser<N> extends Traverser<N> { 374 private final SuccessorsFunction<N> tree; 375 376 TreeTraverser(SuccessorsFunction<N> tree) { 377 this.tree = checkNotNull(tree); 378 } 379 380 @Override 381 public Iterable<N> breadthFirst(final N startNode) { 382 checkNotNull(startNode); 383 checkThatNodeIsInTree(startNode); 384 return new Iterable<N>() { 385 @Override 386 public Iterator<N> iterator() { 387 return new BreadthFirstIterator(startNode); 388 } 389 }; 390 } 391 392 @Override 393 public Iterable<N> depthFirstPreOrder(final N startNode) { 394 checkNotNull(startNode); 395 checkThatNodeIsInTree(startNode); 396 return new Iterable<N>() { 397 @Override 398 public Iterator<N> iterator() { 399 return new DepthFirstPreOrderIterator(startNode); 400 } 401 }; 402 } 403 404 @Override 405 public Iterable<N> depthFirstPostOrder(final N startNode) { 406 checkNotNull(startNode); 407 checkThatNodeIsInTree(startNode); 408 return new Iterable<N>() { 409 @Override 410 public Iterator<N> iterator() { 411 return new DepthFirstPostOrderIterator(startNode); 412 } 413 }; 414 } 415 416 @SuppressWarnings("CheckReturnValue") 417 private void checkThatNodeIsInTree(N startNode) { 418 // successors() throws an IllegalArgumentException for nodes that are not an element of the 419 // graph. 420 tree.successors(startNode); 421 } 422 423 private final class BreadthFirstIterator extends UnmodifiableIterator<N> { 424 private final Queue<N> queue = new ArrayDeque<>(); 425 426 BreadthFirstIterator(N root) { 427 queue.add(root); 428 } 429 430 @Override 431 public boolean hasNext() { 432 return !queue.isEmpty(); 433 } 434 435 @Override 436 public N next() { 437 N current = queue.remove(); 438 Iterables.addAll(queue, tree.successors(current)); 439 return current; 440 } 441 } 442 443 private final class DepthFirstPreOrderIterator extends UnmodifiableIterator<N> { 444 private final Deque<Iterator<? extends N>> stack = new ArrayDeque<>(); 445 446 DepthFirstPreOrderIterator(N root) { 447 stack.addLast(singletonIterator(checkNotNull(root))); 448 } 449 450 @Override 451 public boolean hasNext() { 452 return !stack.isEmpty(); 453 } 454 455 @Override 456 public N next() { 457 Iterator<? extends N> iterator = stack.getLast(); // throws NoSuchElementException if empty 458 N result = checkNotNull(iterator.next()); 459 if (!iterator.hasNext()) { 460 stack.removeLast(); 461 } 462 Iterator<? extends N> childIterator = tree.successors(result).iterator(); 463 if (childIterator.hasNext()) { 464 stack.addLast(childIterator); 465 } 466 return result; 467 } 468 } 469 470 private final class DepthFirstPostOrderIterator extends AbstractIterator<N> { 471 private final ArrayDeque<NodeAndChildren> stack = new ArrayDeque<>(); 472 473 DepthFirstPostOrderIterator(N root) { 474 stack.addLast(withChildren(root)); 475 } 476 477 @Override 478 protected N computeNext() { 479 while (!stack.isEmpty()) { 480 NodeAndChildren top = stack.getLast(); 481 if (top.childIterator.hasNext()) { 482 N child = top.childIterator.next(); 483 stack.addLast(withChildren(child)); 484 } else { 485 stack.removeLast(); 486 return top.node; 487 } 488 } 489 return endOfData(); 490 } 491 492 NodeAndChildren withChildren(N node) { 493 return new NodeAndChildren(node, tree.successors(node)); 494 } 495 496 /** A simple tuple of a node and a partially iterated {@link Iterator} of its children. */ 497 private final class NodeAndChildren { 498 final N node; 499 final Iterator<? extends N> childIterator; 500 501 NodeAndChildren(N node, Iterable<? extends N> children) { 502 this.node = node; 503 this.childIterator = children.iterator(); 504 } 505 } 506 } 507 } 508 509 private enum Order { 510 PREORDER, 511 POSTORDER 512 } 513}