public static List<String> hasCycle( final DAG graph ) { final List<Vertex> vertices = graph.getVertices(); final Map<Vertex, Integer> vertexStateMap = new HashMap<Vertex, Integer>(); List<String> retValue = null; for ( Vertex vertex : vertices ) { if ( isNotVisited( vertex, vertexStateMap ) ) { retValue = introducesCycle( vertex, vertexStateMap ); if ( retValue != null ) { break; } } } return retValue; }
private static boolean dfsVisit( final Vertex vertex, final LinkedList<String> cycle, final Map<Vertex, Integer> vertexStateMap ) { cycle.addFirst( vertex.getLabel() ); vertexStateMap.put( vertex, VISITING ); for ( Vertex v : vertex.getChildren() ) { if ( isNotVisited( v, vertexStateMap ) ) { final boolean hasCycle = dfsVisit( v, cycle, vertexStateMap ); if ( hasCycle ) { return true; } } else if ( isVisiting( v, vertexStateMap ) ) { cycle.addFirst( v.getLabel() ); return true; } } vertexStateMap.put( vertex, VISITED ); cycle.removeFirst(); return false; }
public static List<String> introducesCycle( final Vertex vertex ) { final Map<Vertex, Integer> vertexStateMap = new HashMap<Vertex, Integer>(); return introducesCycle( vertex, vertexStateMap ); }
/** * This method will be called when an edge leading to given vertex was added and we want to check if introduction of * this edge has not resulted in apparition of cycle in the graph * * @param vertex * @param vertexStateMap * @return */ public static List<String> introducesCycle( final Vertex vertex, final Map<Vertex, Integer> vertexStateMap ) { final LinkedList<String> cycleStack = new LinkedList<String>(); final boolean hasCycle = dfsVisit( vertex, cycleStack, vertexStateMap ); if ( hasCycle ) { // we have a situation like: [b, a, c, d, b, f, g, h]. // Label of Vertex which introduced the cycle is at the first position in the list // We have to find second occurrence of this label and use its position in the list // for getting the sublist of vertex labels of cycle participants // // So in our case we are searching for [b, a, c, d, b] final String label = cycleStack.getFirst(); final int pos = cycleStack.lastIndexOf( label ); final List<String> cycle = cycleStack.subList( 0, pos + 1 ); Collections.reverse( cycle ); return cycle; } return null; }
public void addEdge( final Vertex from, final Vertex to ) throws CycleDetectedException { from.addEdgeTo( to ); to.addEdgeFrom( from ); final List<String> cycle = CycleDetector.introducesCycle( to ); if ( cycle != null ) { // remove edge which introduced cycle removeEdge( from, to ); final String msg = "Edge between '" + from + "' and '" + to + "' introduces to cycle in the graph"; throw new CycleDetectedException( msg, cycle ); } }