Cycle Detection in Directed Graph in DSA C - Time & Space Complexity
We want to understand how the time needed to find a cycle in a directed graph changes as the graph grows.
Specifically, how does the process of checking each node and its connections scale?
Analyze the time complexity of the following code snippet.
// Detect cycle using DFS in directed graph
bool dfs(int node, int visited[], int recStack[], List* graph) {
visited[node] = 1;
recStack[node] = 1;
for (int i = 0; i < graph[node].size; i++) {
int neighbor = graph[node].edges[i];
if (!visited[neighbor] && dfs(neighbor, visited, recStack, graph))
return true;
else if (recStack[neighbor])
return true;
}
recStack[node] = 0;
return false;
}
bool isCyclic(int n, List* graph) {
int visited[n];
int recStack[n];
for (int i = 0; i < n; i++) {
visited[i] = 0;
recStack[i] = 0;
}
for (int i = 0; i < n; i++) {
if (!visited[i] && dfs(i, visited, recStack, graph))
return true;
}
return false;
}
This code checks each node using depth-first search to find if a cycle exists in a directed graph.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: DFS visits each node and explores all its edges recursively.
- How many times: Each node is visited once, and each edge is checked once during the DFS calls.
As the number of nodes and edges increase, the DFS explores more connections.
| Input Size (n nodes, e edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 25 operations (visiting nodes + edges) |
| 100 nodes, 200 edges | About 300 operations |
| 1000 nodes, 5000 edges | About 6000 operations |
Pattern observation: The operations grow roughly proportional to the sum of nodes and edges.
Time Complexity: O(n + e)
This means the time grows linearly with the number of nodes plus the number of edges in the graph.
[X] Wrong: "The DFS visits each node multiple times, so the time is much higher than linear."
[OK] Correct: Each node is marked visited and explored only once, so repeated visits do not happen, keeping the time linear.
Understanding this time complexity helps you explain how graph traversal scales and why DFS is efficient for cycle detection.
"What if the graph was represented as an adjacency matrix instead of adjacency lists? How would the time complexity change?"
Practice
Solution
Step 1: Understand cycle in directed graph
A cycle means a path that starts and ends at the same node following the direction of edges.Step 2: Identify what cycle detection finds
Cycle detection checks if such a path exists in the graph.Final Answer:
Whether there is a path that starts and ends at the same node following edge directions -> Option AQuick Check:
Cycle detection = path starting and ending at same node [OK]
- Confusing cycle with shortest path
- Thinking cycle ignores edge directions
- Mixing cycle detection with counting nodes
Solution
Step 1: Understand array declaration in C
In C, to declare an array of size n, use int visited[n]; but it is uninitialized.Step 2: Initialize array to zero
To initialize all elements to zero, use int visited[n] = {0}; which sets all to zero.Final Answer:
int visited[n] = {0}; -> Option BQuick Check:
Array declaration with zero init = int visited[n] = {0}; [OK]
- Using 'new' keyword which is C++ not C
- Declaring array without size
- Incorrect initialization syntax
void dfs(int node, int visited[], int recStack[], int graph[][3]) {
visited[node] = 1;
recStack[node] = 1;
for (int i = 0; i < 3; i++) {
int adj = graph[node][i];
if (adj == -1) continue;
if (!visited[adj]) dfs(adj, visited, recStack, graph);
else if (recStack[adj]) printf("Cycle detected\n");
}
recStack[node] = 0;
}
int main() {
int graph[3][3] = {{1, -1, -1}, {2, -1, -1}, {0, -1, -1}};
int visited[3] = {0}, recStack[3] = {0};
dfs(0, visited, recStack, graph);
return 0;
}Solution
Step 1: Analyze graph edges
Graph edges: 0->1, 1->2, 2->0 form a cycle.Step 2: Trace DFS calls and cycle detection
DFS visits 0, then 1, then 2. When 2 tries to visit 0 again which is in recursion stack, it prints "Cycle detected".Final Answer:
Cycle detected -> Option DQuick Check:
Cycle in graph triggers print "Cycle detected" [OK]
- Ignoring recursion stack for cycle detection
- Assuming no output means no cycle
- Confusing visited and recursion stack arrays
void dfs(int node, int visited[], int graph[][3]) {
visited[node] = 1;
for (int i = 0; i < 3; i++) {
int adj = graph[node][i];
if (adj == -1) continue;
if (!visited[adj]) dfs(adj, visited, graph);
else printf("Cycle detected\n");
}
}
int main() {
int graph[3][3] = {{1, -1, -1}, {2, -1, -1}, {0, -1, -1}};
int visited[3] = {0};
dfs(0, visited, graph);
return 0;
}Solution
Step 1: Understand cycle detection logic
Cycle detection in directed graph needs to track nodes in current recursion path using a recursion stack.Step 2: Identify missing recursion stack
This code only uses visited array, so it cannot distinguish back edges causing cycles from cross edges.Final Answer:
Missing recursion stack to track nodes in current path -> Option CQuick Check:
Recursion stack needed for correct cycle detection [OK]
- Assuming visited array alone detects cycles
- Ignoring need to track current DFS path
- Confusing undirected and directed cycle detection
0: [1] 1: [2] 2: [3, 4] 3: [1] 4: []Which nodes are part of a cycle detected by DFS cycle detection algorithm?
Solution
Step 1: Trace the graph edges
Edges: 0->1, 1->2, 2->3 and 2->4, 3->1.Step 2: Identify cycle nodes
Cycle is 1->2->3->1. Nodes 1, 2, 3 form the cycle.Final Answer:
Nodes 1, 2, 3 -> Option AQuick Check:
Cycle nodes = 1, 2, 3 [OK]
- Including nodes not in cycle like 0 or 4
- Missing node 3 in cycle
- Confusing cycle with path
Ready to prove it?
Pass the test and this pattern moves unknown
