public <S> void findCycles(Nfa<S> nfa, IAcceptor<List<S>> cycleAcceptor) { findCycles(nfa, nfa.getStart(), cycleAcceptor, Maps.newHashMap(), Lists.newLinkedList()); }
/** * A cycle is represented by the set of all nodes on that cycle. The return value maps each node that is on a cycle * to the corresponding set. Multiple cycles that are connected via a node are treated as a single cycle. */ public <S> Map<S, Set<S>> findCycles(Nfa<S> nfa) { Map<S, Set<S>> cycles = Maps.newLinkedHashMap(); IAcceptor<List<S>> cycleAcceptor = new IAcceptor<List<S>>() { @Override public void accept(List<S> t) { Set<S> cycle = Sets.newHashSet(t); for (S cycleNode : t) { // We have two cycles that are connected via at least // one node. Treat them as one cycle. Set<S> existingCycle = cycles.get(cycleNode); if (existingCycle != null) { cycle.addAll(existingCycle); } } for (S n : cycle) { cycles.put(n, cycle); } } }; findCycles(nfa, nfa.getStart(), cycleAcceptor, Maps.<S, Integer>newHashMap(), Lists.<S>newLinkedList()); return cycles; }
protected <S> void findCycles(Nfa<S> nfa, S node, IAcceptor<List<S>> cycleAcceptor, Map<S, Integer> dfsMark, LinkedList<S> dfsStack) { dfsStack.push(node); dfsMark.put(node, DFS_ON_STACK); for (S follower : nfa.getFollowers(node)) { Integer followerMark = dfsMark.get(follower); if (followerMark == null) { // The follower is not visited yet, so go deeper. findCycles(nfa, follower, cycleAcceptor, dfsMark, dfsStack); } else if (followerMark == DFS_ON_STACK) { // If the follower is on the stack that means we have a cycle // that includes all nodes between // the follower node and the current node. LinkedList<S> cycle = Lists.newLinkedList(); Iterator<S> stackIter = dfsStack.iterator(); S cycleNode; do { cycleNode = stackIter.next(); cycle.addFirst(cycleNode); } while (cycleNode != follower && stackIter.hasNext()); cycleAcceptor.accept(cycle); } } dfsStack.pop(); dfsMark.put(node, DFS_VISITED); }