Detect Cycle In A Directed Graph
#include <bits/stdc++.h> // Includes common standard libraries like iostream, unordered_map, list, queue, vector.using namespace std; // Use the standard namespace.
// Function to detect a cycle in a DIRECTED graph using Kahn's Algorithm (BFS-based topological sort).// 'n': Total number of nodes (vertices). Assumed to be 0-indexed (0 to n-1).// 'edges': A vector of pairs, where each pair {u, v} represents a directed edge u -> v.// Returns true if a cycle is detected, false otherwise.bool detectCyclicInDirectedGraph(int n, vector<pair<int, int>> &edges) { // 1. Build Adjacency List and compute In-degrees. unordered_map<int, list<int>> adjList; // Adjacency list for the directed graph. vector<int> indegree(n, 0); // Vector to store in-degree for each node, initialized to 0.
// Populate the adjacency list and calculate in-degrees from the given edges. for(int i = 0; i < edges.size(); i++) { int u = edges[i].first; // Source node. int v = edges[i].second; // Destination node.
adjList[u].push_back(v); // Add directed edge u -> v. indegree[v]++; // Increment in-degree of the destination node 'v'. }
// 2. Initialize Queue with nodes having 0 in-degree. queue<int> qu; // Queue for BFS traversal. int count = 0; // Counter for nodes processed in topological order.
// Enqueue all nodes that have an initial in-degree of 0. for(int i = 0; i < n; i++) { if(indegree[i] == 0) { qu.push(i); } }
// 3. Perform BFS-like traversal (Kahn's algorithm). while(!qu.empty()) { count++; // Increment the count of processed nodes.
int frontVal = qu.front(); // Get the node from the front of the queue. qu.pop(); // Remove it from the queue.
// For each neighbor (x) of the current node (frontVal): // (i.e., for all nodes 'x' that 'frontVal' points to) for(int neighbor : adjList[frontVal]) { indegree[neighbor]--; // Decrement the in-degree of the neighbor. // This simulates removing the edge from 'frontVal' to 'neighbor'.
// If the neighbor's in-degree becomes 0, it means all its prerequisites are met. if(indegree[neighbor] == 0) { qu.push(neighbor); // Enqueue the neighbor for processing. } } }
// 4. Check for cycle. // If 'count' is equal to 'n', it means all nodes were successfully included in the topological sort. // This is only possible if the graph is a Directed Acyclic Graph (DAG). // If 'count' is less than 'n', it implies that some nodes could not be processed (their in-degrees // never dropped to 0), indicating the presence of a cycle. return (count == n) ? false : true;}
int main() { vector<pair<int, int>> edges; // Vector to store the input edges. int n, m; // 'n' for number of nodes, 'm' for number of edges.
cout << "Enter number of nodes : "; cin >> n;
cout << "Enter number of edges : "; cin >> m;
cout << "Enter directed edges (u v, meaning u -> v): " << endl; for(int i = 0; i < m; i++) { int u, v; cin >> u >> v; // Read the source and destination for a directed edge. edges.push_back({u, v}); // Add the edge to the 'edges' vector. }
// Call the function to detect cycles. bool answer = detectCyclicInDirectedGraph(n, edges);
if(answer) { cout << "Cycle is Present" << endl; } else { cout << "Cycle is Not Present" << endl; }
return 0; // Indicate successful execution.}
1. Problem Statement
- Goal: Determine if a directed graph contains any cycles.
- Input: Number of nodes
n
and a list of directed edges(u, v)
(meaningu -> v
). - Output:
true
if a cycle is present,false
otherwise.
2. Core Idea (Kahn’s Algorithm for Cycle Detection)
- Kahn’s algorithm is primarily used for Topological Sorting.
- A topological sort is only possible for Directed Acyclic Graphs (DAGs).
- Key Insight for Cycle Detection: If a directed graph contains a cycle, it’s impossible to perform a complete topological sort that includes all
N
vertices. This is because nodes within a cycle will always have an incoming edge (from within the cycle), meaning their in-degree will never drop to zero until other nodes in the cycle are processed, leading to a deadlock. - Therefore, if the number of nodes in the topological order generated by Kahn’s algorithm is less than the total number of nodes
N
in the graph, it implies the presence of a cycle.
3. Algorithm Steps (detectCyclicInDirectedGraph
function)
-
Build Adjacency List & Calculate In-Degrees:
- Initialize an
adjList
(unordered_map<int, list<int>>
) to represent the directed graph. - Initialize an
indegree
vector (vector<int> indegree(n, 0)
) of sizen
, with all values set to0
. - Iterate through each
edge (u, v)
in the inputedges
:- Add
v
toadjList[u]
(representingu -> v
). - Increment
indegree[v]
(becausev
has an incoming edge fromu
).
- Add
- Initialize an
-
Initialize Queue:
- Create an empty
queue<int> qu
. - Iterate through all nodes from
0
ton-1
. - If
indegree[i] == 0
for any nodei
, pushi
onto thequ
. These are the initial nodes with no prerequisites.
- Create an empty
-
Process Queue (BFS-like):
- Initialize a
count
variable to0
. Thiscount
will track the number of nodes successfully added to the topological order. - While
qu
is not empty:- Increment
count
. frontVal = qu.front(); qu.pop();
(Dequeue the current node).- For each
neighbor (x)
inadjList[frontVal]
(i.e., for all nodesx
thatfrontVal
points to):- Decrement
indegree[x]
. (This simulates removing the edgefrontVal -> x
). - If
indegree[x]
becomes0
, pushx
onto thequ
. (It’s now eligible for processing).
- Decrement
- Increment
- Initialize a
-
Check for Cycle:
- After the BFS-like process completes:
- If
count == n
(meaning alln
nodes were successfully processed and added to the topological order), then the graph is a DAG (no cycle). Returnfalse
. - If
count < n
(meaning some nodes were left behind because their in-degrees never reached zero), then a cycle exists. Returntrue
.
- If
- After the BFS-like process completes:
4. Time and Space Complexity
- Time Complexity:
O(V + E)
- Building
adjList
and calculatingin-degrees
:O(E)
. - Initial queue population:
O(V)
. - BFS traversal (processing queue): Each vertex is enqueued/dequeued once (
O(V)
), and each edge is processed once (O(E)
). - Total:
O(V + E)
.
- Building
- Space Complexity:
O(V + E)
adjList
:O(V + E)
.indegree
vector:O(V)
.queue
:O(V)
in the worst case.