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}