private static <N> boolean subgraphHasCycle(
      Graph<N> graph,
      Map<Object, NodeVisitState> visitedNodes,
      N node,
      @NullableDecl N previousNode) {
    NodeVisitState state = visitedNodes.get(node);
    if (state == NodeVisitState.COMPLETE) {
      return false;
    }
    if (state == NodeVisitState.PENDING) {
      return true;
    }

    visitedNodes.put(node, NodeVisitState.PENDING);
    for (N nextNode : graph.successors(node)) {
      if (canTraverseWithoutReusingEdge(graph, nextNode, previousNode)
          && subgraphHasCycle(graph, visitedNodes, nextNode, node)) {
        return true;
      }
    }
    visitedNodes.put(node, NodeVisitState.COMPLETE);
    return false;
  }
private static <N> boolean subgraphHasCycle(
      Graph<N> graph,
      Map<Object, NodeVisitState> visitedNodes,
      N node,
      @NullableDecl N previousNode) {
    NodeVisitState state = visitedNodes.get(node);
    if (state == NodeVisitState.COMPLETE) {
      return false;
    }
    if (state == NodeVisitState.PENDING) {
      return true;
    }

    visitedNodes.put(node, NodeVisitState.PENDING);
    for (N nextNode : graph.successors(node)) {
      if (canTraverseWithoutReusingEdge(graph, nextNode, previousNode)
          && subgraphHasCycle(graph, visitedNodes, nextNode, node)) {
        return true;
      }
    }
    visitedNodes.put(node, NodeVisitState.COMPLETE);
    return false;
  }
private static < N > boolean subgraphHasCycle ( Graph < N > graph , Map < Object , NodeVisitState > visitedNodes , N node , @ NullableDecl N previousNode ) { NodeVisitState state = visitedNodes . get ( node ) ; if ( state == NodeVisitState . COMPLETE ) { return false ; } if ( state == NodeVisitState . PENDING ) { return true ; } visitedNodes . put ( node , NodeVisitState . PENDING ) ; for ( N nextNode : graph . successors ( node ) ) { if ( canTraverseWithoutReusingEdge ( graph , nextNode , previousNode ) && subgraphHasCycle ( graph , visitedNodes , nextNode , node ) ) { return true ; } } visitedNodes . put ( node , NodeVisitState . COMPLETE ) ; return false ; }
Performs a traversal of the nodes reachable from {@code node}. If we ever reach a node we've
already visited (following only outgoing edges and without reusing edges), we know there's a
cycle in the graph.
Performs a traversal of the nodes reachable from {