Detect Cycle in a Directed Graph
Given the root of a Directed graph, The task is to check whether the graph contains a cycle or not.
Examples:
Input: N = 4, E = 6
Example of graph
Output: Yes
Explanation: The diagram clearly shows a cycle 0 -> 2 -> 0Input: N = 4, E = 4
Output: No
Explanation: The diagram clearly shows no cycle
Approach:
The problem can be solved based on the following idea:
To find cycle in a directed graph we can use the Depth First Traversal (DFS) technique. It is based on the idea that there is a cycle in a graph only if there is a back edge [i.e., a node points to one of its ancestors] present in the graph.
To detect a back edge, we need to keep track of the nodes visited till now and the nodes that are in the current recursion stack [i.e., the current path that we are visiting]. If during recursion, we reach a node that is already in the recursion stack, there is a cycle present in the graph.
Note: If the graph is disconnected then get the DFS forest and check for a cycle in individual trees by checking back edges.
Follow the below steps to Implement the idea:
- Create a recursive dfs function that has the following parameters – current vertex, visited array, and recursion stack.
- Mark the current node as visited and also mark the index in the recursion stack.
- Iterate a loop for all the vertices and for each vertex, call the recursive function if it is not yet visited (This step is done to make sure that if there is a forest of graphs, we are checking each forest):
- In each recursion call, Find all the adjacent vertices of the current vertex which are not visited:
- If an adjacent vertex is already marked in the recursion stack then return true.
- Otherwise, call the recursive function for that adjacent vertex.
- While returning from the recursion call, unmark the current node from the recursion stack, to represent that the current node is no longer a part of the path being traced.
- In each recursion call, Find all the adjacent vertices of the current vertex which are not visited:
- If any of the functions returns true, stop the future function calls and return true as the answer.
Illustration:
Consider the following graph:

Example of a Directed Graph
Consider we start the iteration from vertex 0.
- Initially, 0 will be marked in both the visited[] and recStack[] array as it is a part of the current path.
Vertex 0 is visited
- Now 0 has two adjacent vertices 1 and 2. Let us consider traversal to the vertex 1. So 1 will be marked in both visited[] and recStack[].
Vertex 1 is visited
- Vertex 1 has only one adjacent vertex. Call the recursive function for 2 and mark it in visited[] and recStack[].
Vertex 2 is visited
- Vertex 2 also has two adjacent vertices.
- Vertex 0 is visited and already marked in the recStack[]. So if 0 is checked first, we will get the answer that there is a cycle present.
- On the other hand, if vertex 3 is checked first, then 3 will be marked in visited[] and recStack[].
Vertex 3 is visited
- While returning from the recursion call for 3, it will be unmarked from recStack[] as it is now not a part of the path currently being traced.
Vertex 3 is unmarked from recStack[]
- Now we have only one option to check, vertex 0, which is already marked in recStack[].
So, we can conclude that a cycle exists. We can also find the cycle if we have traversed to vertex 2 from 0 itself in this same way.
Below is the implementation of the above approach:
C++
// A C++ Program to detect cycle in a graph #include <bits/stdc++.h> using namespace std; class Graph { // No. of vertices int V; // Pointer to an array containing adjacency lists list< int >* adj; // Used by isCyclic() bool isCyclicUtil( int v, bool visited[], bool * rs); public : Graph( int V); void addEdge( int v, int w); bool isCyclic(); }; Graph::Graph( int V) { this ->V = V; adj = new list< int >[V]; } void Graph::addEdge( int v, int w) { // Add w to v’s list. adj[v].push_back(w); } // DFS function to find if a cycle exists bool Graph::isCyclicUtil( int v, bool visited[], bool * recStack) { if (visited[v] == false ) { // Mark the current node as visited // and part of recursion stack visited[v] = true ; recStack[v] = true ; // Recur for all the vertices adjacent to this // vertex list< int >::iterator i; for (i = adj[v].begin(); i != adj[v].end(); ++i) { if (!visited[*i] && isCyclicUtil(*i, visited, recStack)) return true ; else if (recStack[*i]) return true ; } } // Remove the vertex from recursion stack recStack[v] = false ; return false ; } // Returns true if the graph contains a cycle, else false bool Graph::isCyclic() { // Mark all the vertices as not visited // and not part of recursion stack bool * visited = new bool [V]; bool * recStack = new bool [V]; for ( int i = 0; i < V; i++) { visited[i] = false ; recStack[i] = false ; } // Call the recursive helper function // to detect cycle in different DFS trees for ( int i = 0; i < V; i++) if (!visited[i] && isCyclicUtil(i, visited, recStack)) return true ; return false ; } // Driver code int main() { // Create a graph Graph g(4); g.addEdge(0, 1); g.addEdge(0, 2); g.addEdge(1, 2); g.addEdge(2, 0); g.addEdge(2, 3); g.addEdge(3, 3); // Function call if (g.isCyclic()) cout << "Graph contains cycle" ; else cout << "Graph doesn't contain cycle" ; return 0; } |
Java
// A Java Program to detect cycle in a graph import java.util.ArrayList; import java.util.LinkedList; import java.util.List; class Graph { private final int V; private final List<List<Integer>> adj; public Graph( int V) { this .V = V; adj = new ArrayList<>(V); for ( int i = 0 ; i < V; i++) adj.add( new LinkedList<>()); } // Function to check if cycle exists private boolean isCyclicUtil( int i, boolean [] visited, boolean [] recStack) { // Mark the current node as visited and // part of recursion stack if (recStack[i]) return true ; if (visited[i]) return false ; visited[i] = true ; recStack[i] = true ; List<Integer> children = adj.get(i); for (Integer c: children) if (isCyclicUtil(c, visited, recStack)) return true ; recStack[i] = false ; return false ; } private void addEdge( int source, int dest) { adj.get(source).add(dest); } // Returns true if the graph contains a // cycle, else false. private boolean isCyclic() { // Mark all the vertices as not visited and // not part of recursion stack boolean [] visited = new boolean [V]; boolean [] recStack = new boolean [V]; // Call the recursive helper function to // detect cycle in different DFS trees for ( int i = 0 ; i < V; i++) if (isCyclicUtil(i, visited, recStack)) return true ; return false ; } // Driver code public static void main(String[] args) { Graph graph = new Graph( 4 ); graph.addEdge( 0 , 1 ); graph.addEdge( 0 , 2 ); graph.addEdge( 1 , 2 ); graph.addEdge( 2 , 0 ); graph.addEdge( 2 , 3 ); graph.addEdge( 3 , 3 ); // Function call if (graph.isCyclic()) System.out.println( "Graph contains cycle" ); else System.out.println( "Graph doesn't " + "contain cycle" ); } } // This code is contributed by Sagar Shah. |
Python3
# Python program to detect cycle # in a graph from collections import defaultdict class Graph(): def __init__( self , vertices): self .graph = defaultdict( list ) self .V = vertices def addEdge( self , u, v): self .graph[u].append(v) def isCyclicUtil( self , v, visited, recStack): # Mark current node as visited and # adds to recursion stack visited[v] = True recStack[v] = True # Recur for all neighbours # if any neighbour is visited and in # recStack then graph is cyclic for neighbour in self .graph[v]: if visited[neighbour] = = False : if self .isCyclicUtil(neighbour, visited, recStack) = = True : return True elif recStack[neighbour] = = True : return True # The node needs to be popped from # recursion stack before function ends recStack[v] = False return False # Returns true if graph is cyclic else false def isCyclic( self ): visited = [ False ] * ( self .V + 1 ) recStack = [ False ] * ( self .V + 1 ) for node in range ( self .V): if visited[node] = = False : if self .isCyclicUtil(node, visited, recStack) = = True : return True return False # Driver code if __name__ = = '__main__' : g = Graph( 4 ) g.addEdge( 0 , 1 ) g.addEdge( 0 , 2 ) g.addEdge( 1 , 2 ) g.addEdge( 2 , 0 ) g.addEdge( 2 , 3 ) g.addEdge( 3 , 3 ) if g.isCyclic() = = 1 : print ( "Graph contains cycle" ) else : print ( "Graph doesn't contain cycle" ) # Thanks to Divyanshu Mehta for contributing this code |
C#
// A C# Program to detect cycle in a graph using System; using System.Collections.Generic; public class Graph { private readonly int V; private readonly List<List< int > > adj; public Graph( int V) { this .V = V; adj = new List<List< int > >(V); for ( int i = 0; i < V; i++) adj.Add( new List< int >()); } // Function to check if cycle exists private bool isCyclicUtil( int i, bool [] visited, bool [] recStack) { // Mark the current node as visited and // part of recursion stack if (recStack[i]) return true ; if (visited[i]) return false ; visited[i] = true ; recStack[i] = true ; List< int > children = adj[i]; foreach ( int c in children) if ( isCyclicUtil(c, visited, recStack)) return true ; recStack[i] = false ; return false ; } private void addEdge( int sou, int dest) { adj[sou].Add(dest); } // Returns true if the graph contains a // cycle, else false private bool isCyclic() { // Mark all the vertices as not visited and // not part of recursion stack bool [] visited = new bool [V]; bool [] recStack = new bool [V]; // Call the recursive helper function to // detect cycle in different DFS trees for ( int i = 0; i < V; i++) if (isCyclicUtil(i, visited, recStack)) return true ; return false ; } // Driver code public static void Main(String[] args) { Graph graph = new Graph(4); graph.addEdge(0, 1); graph.addEdge(0, 2); graph.addEdge(1, 2); graph.addEdge(2, 0); graph.addEdge(2, 3); graph.addEdge(3, 3); // Function call if (graph.isCyclic()) Console.WriteLine( "Graph contains cycle" ); else Console.WriteLine( "Graph doesn't " + "contain cycle" ); } } // This code contributed by Rajput-Ji |
Javascript
// A JavaScript Program to detect cycle in a graph let V; let adj=[]; function Graph(v) { V=v; for (let i = 0; i < V; i++) adj.push([]); } // Function to check if cycle exists function isCyclicUtil(i,visited,recStack) { // Mark the current node as visited and // part of recursion stack if (recStack[i]) return true ; if (visited[i]) return false ; visited[i] = true ; recStack[i] = true ; let children = adj[i]; for (let c=0;c< children.length;c++) if (isCyclicUtil(children, visited, recStack)) return true ; recStack[i] = false ; return false ; } function addEdge(source,dest) { adj .push(dest); } // Returns true if the graph contains a // cycle, else false. function isCyclic() { // Mark all the vertices as not visited and // not part of recursion stack let visited = new Array(V); let recStack = new Array(V); for (let i=0;i<V;i++) { visited[i]= false ; recStack[i]= false ; } // Call the recursive helper function to // detect cycle in different DFS trees for (let i = 0; i < V; i++) if (isCyclicUtil(i, visited, recStack)) return true ; return false ; } // Driver code Graph(4); addEdge(0, 1); addEdge(0, 2); addEdge(1, 2); addEdge(2, 0); addEdge(2, 3); addEdge(3, 3); if (isCyclic()) console.log( "Graph contains cycle" ); else console.log( "Graph doesn't " + "contain cycle" ); // This code is contributed by patel2127 |
Graph contains cycle
Time Complexity: O(V + E), the Time Complexity of this method is the same as the time complexity of DFS traversal which is O(V+E).
Auxiliary Space: O(V). To store the visited and recursion stack O(V) space is needed.
In the below article, another O(V + E) method is discussed :
Detect Cycle in a direct graph using colors
Please Login to comment...