public class CycleDetector {
    
    private boolean[] visited; 
    private boolean hasCycle;  // cached answer to the question - does the graph have a cycle?
    
    public CycleDetector(Graph g) {
        visited = new boolean[g.numVertices()]; 
        hasCycle = false; //superfluous
        for (int s = 0; s < g.numVertices(); s++)  // iterate through several "sources" s to search all connected components
            if (!visited[s])
                dfs(g,s,s);  // note the additional argument! (see comment concerning special case in dfs() method below)
    }
    
    private void dfs(Graph g, int v, int u) {  // i.e., do a dfs from v, (which came from u)
        visited[v] = true;
        for (int w : g.adj(v)) {
            if (!visited[w]) {
                dfs(g,w,v);
            }
            else if (w != u)       // if v came from u, then u will be one of the vertices w adjacent to v,
                hasCycle = true;   // and u will ALWAYS be already visited -- so we expect visited[u]==true.  But if we reach
        }                          // out from w and find some other visited vertex, we've got a cycle!
    }                              // SPECIAL CASE: sources s don't "come from" anywhere.  By calling dfs() with u = v for these,
                                   // note that the "else if" would execute for EVERY visited adj w to s -- but when the source s
                                   // is first considered, all visited vertices are in a different component, so the "else if"
                                   // NEVER executes for a source (which is good, as it is too early to form a cycle)
    
    public boolean hasCycle() {   // once established by the constructor, we just retrieve the cached result
        return this.hasCycle;
    }
    
    public static void main(String[] args) {
        
        Graph g = new Graph(7);
        g.addEdge(0, 1);
        g.addEdge(0, 6);
        g.addEdge(1, 3);
        g.addEdge(1, 5);
        g.addEdge(1, 6);
        g.addEdge(2, 3);
        g.addEdge(2, 5);
        g.addEdge(2, 6);
        g.addEdge(3, 4);
        g.addEdge(4, 5);
        System.out.println(g);
        
        Graph h = new Graph(7);
        h.addEdge(0, 1);
        h.addEdge(1, 2);
        h.addEdge(1, 4);
        h.addEdge(2, 5);
        h.addEdge(2, 6);
        h.addEdge(3, 4);
        System.out.println(h);
        
        CycleDetector cdg = new CycleDetector(g);
        System.out.println(cdg.hasCycle());
        
        CycleDetector cdh = new CycleDetector(h);
        System.out.println(cdh.hasCycle());
    }
}
