Top Description Inners Fields Constructors Methods
com.google.common.graph

public abstract Class Traverser<N>

extends Object
Class Inheritance
Annotations
@Beta
@DoNotMock:Call forGraph or forTree, passing a lambda or a Graph with the desired edges (built with GraphBuilder)
@ElementTypesAreNonnullByDefault
Type Parameters
<N>
Node parameter type
Static Imports
com.google.common.base.Preconditions.checkArgument, .Preconditions.checkNotNull, java.util.Objects.requireNonNull

An object that can traverse the nodes that are reachable from a specified (set of) start node(s) using a specified SuccessorsFunction.

There are two entry points for creating a Traverser: forTree(SuccessorsFunction) and forGraph(SuccessorsFunction). You should choose one based on your answers to the following questions:

  1. Is there only one path to any node that's reachable from any start node? (If so, the graph to be traversed is a tree or forest even if it is a subgraph of a graph which is neither.)
  2. Are the node objects' implementations of equals()/hashCode() recursive?

If your answers are:

Author
Jens Nyman
Since
23.1

Nested and Inner Type Summary

Modifier and TypeClass and Description
private static enum
Traverser.InsertionOrder

Poor man's method reference for Deque::addFirst and Deque::addLast.

private abstract static class
Traverser.Traversal<N>

Abstracts away the difference between traversing a graph vs. a tree.

Field Summary

Modifier and TypeField and Description
private final SuccessorsFunction<N>

Constructor Summary

AccessConstructor and Description
private
Traverser(SuccessorsFunction<N> successorFunction)

Method Summary

Modifier and TypeMethod and Description
public final Iterable<N>
breadthFirst(N startNode)

Returns an unmodifiable Iterable over the nodes reachable from startNode, in the order of a breadth-first traversal.

public final Iterable<N>
breadthFirst(Iterable<? extends N> startNodes)

Returns an unmodifiable Iterable over the nodes reachable from any of the startNodes, in the order of a breadth-first traversal.

public final Iterable<N>
depthFirstPostOrder(N startNode)

Returns an unmodifiable Iterable over the nodes reachable from startNode, in the order of a depth-first post-order traversal.

public final Iterable<N>
depthFirstPostOrder(Iterable<? extends N> startNodes)

Returns an unmodifiable Iterable over the nodes reachable from any of the startNodes, in the order of a depth-first post-order traversal.

public final Iterable<N>
depthFirstPreOrder(N startNode)

Returns an unmodifiable Iterable over the nodes reachable from startNode, in the order of a depth-first pre-order traversal.

public final Iterable<N>
depthFirstPreOrder(Iterable<? extends N> startNodes)

Returns an unmodifiable Iterable over the nodes reachable from any of the startNodes, in the order of a depth-first pre-order traversal.

public static <N> Traverser<N>
forGraph(SuccessorsFunction<N>
SuccessorsFunction representing a general graph that may have cycles.
graph
)

Creates a new traverser for the given general graph.

public static <N> Traverser<N>
forTree(SuccessorsFunction<N>
SuccessorsFunction representing a directed acyclic graph that has at most one path between any two nodes
tree
)

Creates a new traverser for a directed acyclic graph that has at most one path from the start node(s) to any node reachable from the start node(s), and has no paths from any start node to any other start node, such as a tree or forest.

pack-priv abstract Traverser.Traversal<N>
private ImmutableSet<N>
validate(Iterable<? extends N> startNodes)

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

successorFunctionback to summary
private final SuccessorsFunction<N> successorFunction

Constructor Detail

Traverserback to summary
private Traverser(SuccessorsFunction<N> successorFunction)

Method Detail

breadthFirstback to summary
public final Iterable<N> breadthFirst(N startNode)

Returns an unmodifiable Iterable over the nodes reachable from startNode, in the order of a breadth-first traversal. That is, all the nodes of depth 0 are returned, then depth 1, then 2, and so on.

Example: The following graph with startNode a would return nodes in the order abcdef (assuming successors are returned in alphabetical order).

b ---- a ---- d
|      |
|      |
e ---- c ---- f

The behavior of this method is undefined if the nodes, or the topology of the graph, change while iteration is in progress.

The returned Iterable can be iterated over multiple times. Every iterator will compute its next element on the fly. It is thus possible to limit the traversal to a certain number of nodes as follows:

Iterables.limit(Traverser.forGraph(graph).breadthFirst(node), maxNumberOfNodes);

See Wikipedia for more info.

Exceptions
IllegalArgumentException:
if startNode is not an element of the graph
breadthFirstback to summary
public final Iterable<N> breadthFirst(Iterable<? extends N> startNodes)

Returns an unmodifiable Iterable over the nodes reachable from any of the startNodes, in the order of a breadth-first traversal. This is equivalent to a breadth-first traversal of a graph with an additional root node whose successors are the listed startNodes.

Exceptions
IllegalArgumentException:
if any of startNodes is not an element of the graph
Since
24.1
See Also
breadthFirst(Object)
depthFirstPostOrderback to summary
public final Iterable<N> depthFirstPostOrder(N startNode)

Returns an unmodifiable Iterable over the nodes reachable from startNode, in the order of a depth-first post-order traversal. "Post-order" implies that nodes appear in the Iterable in the order in which they are visited for the last time.

Example: The following graph with startNode a would return nodes in the order fcebda (assuming successors are returned in alphabetical order).

b ---- a ---- d
|      |
|      |
e ---- c ---- f

The behavior of this method is undefined if the nodes, or the topology of the graph, change while iteration is in progress.

The returned Iterable can be iterated over multiple times. Every iterator will compute its next element on the fly. It is thus possible to limit the traversal to a certain number of nodes as follows:

Iterables.limit(
    Traverser.forGraph(graph).depthFirstPostOrder(node), maxNumberOfNodes);

See Wikipedia for more info.

Exceptions
IllegalArgumentException:
if startNode is not an element of the graph
depthFirstPostOrderback to summary
public final Iterable<N> depthFirstPostOrder(Iterable<? extends N> startNodes)

Returns an unmodifiable Iterable over the nodes reachable from any of the startNodes, in the order of a depth-first post-order traversal. This is equivalent to a depth-first post-order traversal of a graph with an additional root node whose successors are the listed startNodes.

Exceptions
IllegalArgumentException:
if any of startNodes is not an element of the graph
Since
24.1
See Also
depthFirstPostOrder(Object)
depthFirstPreOrderback to summary
public final Iterable<N> depthFirstPreOrder(N startNode)

Returns an unmodifiable Iterable over the nodes reachable from startNode, in the order of a depth-first pre-order traversal. "Pre-order" implies that nodes appear in the Iterable in the order in which they are first visited.

Example: The following graph with startNode a would return nodes in the order abecfd (assuming successors are returned in alphabetical order).

b ---- a ---- d
|      |
|      |
e ---- c ---- f

The behavior of this method is undefined if the nodes, or the topology of the graph, change while iteration is in progress.

The returned Iterable can be iterated over multiple times. Every iterator will compute its next element on the fly. It is thus possible to limit the traversal to a certain number of nodes as follows:

Iterables.limit(
    Traverser.forGraph(graph).depthFirstPreOrder(node), maxNumberOfNodes);

See Wikipedia for more info.

Exceptions
IllegalArgumentException:
if startNode is not an element of the graph
depthFirstPreOrderback to summary
public final Iterable<N> depthFirstPreOrder(Iterable<? extends N> startNodes)

Returns an unmodifiable Iterable over the nodes reachable from any of the startNodes, in the order of a depth-first pre-order traversal. This is equivalent to a depth-first pre-order traversal of a graph with an additional root node whose successors are the listed startNodes.

Exceptions
IllegalArgumentException:
if any of startNodes is not an element of the graph
Since
24.1
See Also
depthFirstPreOrder(Object)
forGraphback to summary
public static <N> Traverser<N> forGraph(SuccessorsFunction<N> graph)

Creates a new traverser for the given general graph.

Traversers created using this method are guaranteed to visit each node reachable from the start node(s) at most once.

If you know that no node in graph is reachable by more than one path from the start node(s), consider using forTree(SuccessorsFunction) instead.

Performance notes

  • Traversals require O(n) time (where n is the number of nodes reachable from the start node), assuming that the node objects have O(1) equals() and hashCode() implementations. (See the notes on element objects for more information.)
  • While traversing, the traverser will use O(n) space (where n is the number of nodes that have thus far been visited), plus O(H) space (where H is the number of nodes that have been seen but not yet visited, that is, the "horizon").
Parameters
graph:SuccessorsFunction<N>

SuccessorsFunction representing a general graph that may have cycles.

forTreeback to summary
public static <N> Traverser<N> forTree(SuccessorsFunction<N> tree)

Creates a new traverser for a directed acyclic graph that has at most one path from the start node(s) to any node reachable from the start node(s), and has no paths from any start node to any other start node, such as a tree or forest.

forTree() is especially useful (versus forGraph()) in cases where the data structure being traversed is, in addition to being a tree/forest, also defined recursively. This is because the forTree()-based implementations don't keep track of visited nodes, and therefore don't need to call `equals()` or `hashCode()` on the node objects; this saves both time and space versus traversing the same graph using forGraph().

Providing a graph to be traversed for which there is more than one path from the start node(s) to any node may lead to:

  • Traversal not terminating (if the graph has cycles)
  • Nodes being visited multiple times (if multiple paths exist from any start node to any node reachable from any start node)

Performance notes

  • Traversals require O(n) time (where n is the number of nodes reachable from the start node).
  • While traversing, the traverser will use O(H) space (where H is the number of nodes that have been seen but not yet visited, that is, the "horizon").

Examples (all edges are directed facing downwards)

The graph below would be valid input with start nodes of a, f, c. However, if b were also a start node, then there would be multiple paths to reach e and h.

a     b      c
  / \   / \     |
 /   \ /   \    |
d     e     f   g
      |
      |
      h

.

The graph below would be a valid input with start nodes of a, f. However, if b were a start node, there would be multiple paths to f.

a     b
  / \   / \
 /   \ /   \
c     d     e
       \   /
        \ /
         f

Note on binary trees

This method can be used to traverse over a binary tree. Given methods leftChild(node) and rightChild(node), this method can be called as

Traverser.forTree(node -> ImmutableList.of(leftChild(node), rightChild(node)));
Parameters
tree:SuccessorsFunction<N>

SuccessorsFunction representing a directed acyclic graph that has at most one path between any two nodes

newTraversalback to summary
pack-priv abstract Traverser.Traversal<N> newTraversal()
validateback to summary
private ImmutableSet<N> validate(Iterable<? extends N> startNodes)
Annotations
@SuppressWarnings:CheckReturnValue
com.google.common.graph back to summary

private sealed Enum Traverser.InsertionOrder

extends Enum<Traverser.InsertionOrder>
Class Inheritance

Poor man's method reference for Deque::addFirst and Deque::addLast.

Field Summary

Modifier and TypeField and Description
public static final Traverser.InsertionOrder
public static final Traverser.InsertionOrder

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
pack-priv abstract <T> void
insertInto(Deque<T> deque, T value)

public static Traverser.InsertionOrder
public static Traverser.InsertionOrder[]
Inherited from java.lang.Enum:
clonecompareTodescribeConstableequalsfinalizegetDeclaringClasshashCodenameordinaltoStringvalueOf

Field Detail

BACKback to summary
public static final Traverser.InsertionOrder BACK
FRONTback to summary
public static final Traverser.InsertionOrder FRONT

Constructor Detail

InsertionOrderback to summary
private InsertionOrder()

Method Detail

insertIntoback to summary
pack-priv abstract <T> void insertInto(Deque<T> deque, T value)
valueOfback to summary
public static Traverser.InsertionOrder valueOf(String name)
valuesback to summary
public static Traverser.InsertionOrder[] values()
com.google.common.graph back to summary

private abstract Class Traverser.Traversal<N>

extends Object
Class Inheritance

Abstracts away the difference between traversing a graph vs. a tree. For a tree, we just take the next element from the next non-empty iterator; for graph, we need to loop through the next non-empty iterator to find first unvisited node.

Field Summary

Modifier and TypeField and Description
pack-priv final SuccessorsFunction<N>

Constructor Summary

AccessConstructor and Description
pack-priv
Traversal(SuccessorsFunction<N> successorFunction)

Method Summary

Modifier and TypeMethod and Description
pack-priv final Iterator<N>
breadthFirst(Iterator<? extends N> startNodes)

pack-priv static <N> Traverser.Traversal<N>
pack-priv static <N> Traverser.Traversal<N>
pack-priv final Iterator<N>
postOrder(Iterator<? extends N> startNodes)

pack-priv final Iterator<N>
preOrder(Iterator<? extends N> startNodes)

private Iterator<N>
topDown(Iterator<? extends N> startNodes, Traverser.InsertionOrder order)

In top-down traversal, an ancestor node is always traversed before any of its descendant nodes.

pack-priv abstract N
visitNext(Deque<Iterator<? extends N>> horizon)

Visits the next node from the top iterator of horizon and returns the visited node.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

successorFunctionback to summary
pack-priv final SuccessorsFunction<N> successorFunction

Constructor Detail

Traversalback to summary
pack-priv Traversal(SuccessorsFunction<N> successorFunction)

Method Detail

breadthFirstback to summary
pack-priv final Iterator<N> breadthFirst(Iterator<? extends N> startNodes)
inGraphback to summary
pack-priv static <N> Traverser.Traversal<N> inGraph(SuccessorsFunction<N> graph)
inTreeback to summary
pack-priv static <N> Traverser.Traversal<N> inTree(SuccessorsFunction<N> tree)
postOrderback to summary
pack-priv final Iterator<N> postOrder(Iterator<? extends N> startNodes)
preOrderback to summary
pack-priv final Iterator<N> preOrder(Iterator<? extends N> startNodes)
topDownback to summary
private Iterator<N> topDown(Iterator<? extends N> startNodes, Traverser.InsertionOrder order)

In top-down traversal, an ancestor node is always traversed before any of its descendant nodes. The traversal order among descendant nodes (particularly aunts and nieces) are determined by the InsertionOrder parameter: nieces are placed at the FRONT before aunts for pre-order; while in BFS they are placed at the BACK after aunts.

visitNextback to summary
pack-priv abstract N visitNext(Deque<Iterator<? extends N>> horizon)

Visits the next node from the top iterator of horizon and returns the visited node. Null is returned to indicate reaching the end of the top iterator.

For example, if horizon is [[a, b], [c, d], [e]], visitNext() will return [a, b, null, c, d, null, e, null] sequentially, encoding the topological structure. (Note, however, that the callers of visitNext() often insert additional iterators into horizon between calls to visitNext(). This causes them to receive additional values interleaved with those shown above.)

Annotations
@CheckForNull