Cycle Detection In Undirected Graph Using BFS
#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 an UNDIRECTED graph using BFS.// 'adjList': The adjacency list of the graph.// 'visited': A map to keep track of globally visited nodes.// 'Node': The starting node for the current BFS traversal (component).bool isCyclicBFS(unordered_map<int, list<int>> &adjList, unordered_map<int, bool> &visited, int Node) { // 'parent' map stores the parent of each node in the BFS tree. unordered_map<int, int> parent; parent[Node] = -1; // The starting node has no parent.
visited[Node] = true; // Mark the starting node as visited.
queue<int> Q; // Create a queue for BFS. Q.push(Node); // Enqueue the starting node.
// BFS traversal loop. while(!Q.empty()) { int FrontVal = Q.front(); // Get the current node from the front of the queue. Q.pop(); // Remove it from the queue.
// Iterate through all neighbors of the current node. for(int neighbor : adjList[FrontVal]) { // Case 1: Neighbor is already visited. // If the visited neighbor is NOT the parent of the current node, then a cycle is found. // This means we found a path to 'neighbor' that doesn't go through 'FrontVal's parent. if(visited[neighbor] == true && parent[FrontVal] != neighbor) { return true; // Cycle detected! }
// Case 2: Neighbor is not visited. // Explore this unvisited neighbor. if(visited[neighbor] == false) { visited[neighbor] = true; // Mark neighbor as visited. parent[neighbor] = FrontVal; // Set current node as neighbor's parent. Q.push(neighbor); // Enqueue the neighbor for further exploration. } } }
return false; // No cycle found in this connected component.}
// Main function to check for cycles in an undirected graph.// 'edges': A vector of vectors representing the graph edges (e.g., {{u,v}, {x,y}}).// 'n': Total number of nodes.// 'm': Total number of edges.// Returns "YES" if a cycle is detected, "NO" otherwise.string cycleDetection(vector<vector<int>> &edges, int n, int m) { // Adjacency list to represent the graph. unordered_map<int, list<int>> adjList; // Map to keep track of visited nodes across all components. unordered_map<int, bool> visited;
// Create Adjacency List from the input edges (for undirected graph). for(int i = 0; i < m; i++) { int u = edges[i][0]; int v = edges[i][1];
adjList[u].push_back(v); adjList[v].push_back(u); // Add edge in both directions for undirected graph. }
// Iterate through all nodes to handle disconnected graph components. // Assuming nodes are 1-indexed here, based on loop 'i=1; i<=n'. for(int i = 1; i <= n; i++) { // If the current node 'i' has not been visited yet, start a BFS from it. if(visited[i] == false) { // Call isCyclicBFS to check for a cycle in the component starting at 'i'. bool ans = isCyclicBFS(adjList, visited, i);
// If a cycle is found in any component, the graph contains a cycle. if(ans) { return "YES"; } } }
// If no cycle was found after checking all components, the graph is acyclic. return "NO";}
int main() { int n, m; vector<vector<int>> edges; // Vector to store the input edges.
cout << "Enter the total number of nodes : "; cin >> n;
cout << "Enter total number of edges : "; cin >> m;
cout << "Enter edges (u v): " << endl; for(int i = 0; i < m; i++) { int u, v; cin >> u >> v; // Read the two nodes for an edge. edges.push_back({u, v}); // Add the edge to the 'edges' vector. }
// Call cycleDetection to check for cycles. string ans = cycleDetection(edges, n, m);
cout << "Cycle Detection Result : " << ans << endl;
return 0; // Indicate successful execution.}
1. Problem Statement
- Goal: Determine if an undirected graph contains any cycles.
- Input: Number of nodes
n
, number of edgesm
, and a list of edges(u, v)
. - Output: “YES” if a cycle is present, “NO” otherwise.
2. What is a Cycle?
- A cycle in a graph is a path that starts and ends at the same vertex, and where no vertex (other than the start/end vertex) is visited more than once.
3. Core Idea for Undirected Graphs with BFS
- When performing a BFS traversal, we keep track of the
parent
of each visited node. - If, during the BFS, we encounter a
visited
node that is not the current node’s immediateparent
, it means we’ve found a back-edge, which indicates a cycle.- Why? If a neighbor
V
of current nodeU
is alreadyvisited
andV
is not theparent
from whichU
was reached, it implies there’s another path from the source toV
that doesn’t go throughU
’s parent. This forms a closed loop.
- Why? If a neighbor
4. Algorithm Steps (isCyclicBFS
function)
-
Initialization:
adjList
: Adjacency list of the graph.visited
:unordered_map<int, bool>
to mark visited nodes.parent
:unordered_map<int, int>
to store the parent of each node in the BFS tree.- Queue (
Q
): For BFS traversal. - Start Node: Push the
Node
(the current component’s starting point) intoQ
. - Mark Visited & Parent:
visited[Node] = true; parent[Node] = -1;
(Parent of source is typically -1 or some sentinel).
-
BFS Loop: While
Q
is not empty:- Dequeue: Get
FrontVal
fromQ
andpop
it. - Explore Neighbors: For each
neighbor
(i
) inadjList[FrontVal]
:- Cycle Condition: If
neighbor
isvisited
ANDneighbor
is not theparent
ofFrontVal
:- A cycle is detected. Return
true
.
- A cycle is detected. Return
- Unvisited Neighbor: If
neighbor
isnot visited
:- Mark
visited[neighbor] = true
. - Set
parent[neighbor] = FrontVal
. - Enqueue
neighbor
.
- Mark
- Cycle Condition: If
- Dequeue: Get
-
No Cycle in Component: If the BFS loop finishes without returning
true
, it means no cycle was found in the current connected component. Returnfalse
.
5. Overall Cycle Detection (cycleDetection
function)
- Adjacency List Creation: First, build the
adjList
from the inputedges
. For undirected graphs, add edgesu->v
andv->u
. - Handling Disconnected Graphs: Iterate through all possible nodes (
for i = 1 to n
).- If a node
i
has not beenvisited
yet (meaning it’s part of a new connected component):- Call
isCyclicBFS(adjList, visited, i)
. - If
isCyclicBFS
returnstrue
, then a cycle exists in the graph. Immediately return “YES”.
- Call
- If a node
- No Cycle Found: If the loop completes and no cycle was detected in any component, return “NO”.
6. Time and Space Complexity
- Time Complexity:
O(V + E)
- Building
adjList
:O(M)
(whereM
is number of edges). isCyclicBFS
: Each vertex and edge is visited at most once.O(V + E)
.- Outer loop in
cycleDetection
: IteratesV
times, butisCyclicBFS
only runs on unvisited components. So, total sum ofisCyclicBFS
calls across all components isO(V + E)
.
- Building
- Space Complexity:
O(V + E)
adjList
:O(V + E)
.visited
map:O(V)
.parent
map:O(V)
.Queue
:O(V)
in worst case.