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}