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
parentof each visited node. - If, during the BFS, we encounter a
visitednode that is not the current node’s immediateparent, it means we’ve found a back-edge, which indicates a cycle.- Why? If a neighbor
Vof current nodeUis alreadyvisitedandVis not theparentfrom whichUwas reached, it implies there’s another path from the source toVthat 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
Qis not empty:- Dequeue: Get
FrontValfromQandpopit. - Explore Neighbors: For each
neighbor(i) inadjList[FrontVal]:- Cycle Condition: If
neighborisvisitedANDneighboris not theparentofFrontVal:- A cycle is detected. Return
true.
- A cycle is detected. Return
- Unvisited Neighbor: If
neighborisnot 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
adjListfrom the inputedges. For undirected graphs, add edgesu->vandv->u. - Handling Disconnected Graphs: Iterate through all possible nodes (
for i = 1 to n).- If a node
ihas not beenvisitedyet (meaning it’s part of a new connected component):- Call
isCyclicBFS(adjList, visited, i). - If
isCyclicBFSreturnstrue, 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)(whereMis number of edges). isCyclicBFS: Each vertex and edge is visited at most once.O(V + E).- Outer loop in
cycleDetection: IteratesVtimes, butisCyclicBFSonly runs on unvisited components. So, total sum ofisCyclicBFScalls across all components isO(V + E).
- Building
- Space Complexity:
O(V + E)adjList:O(V + E).visitedmap:O(V).parentmap:O(V).Queue:O(V)in worst case.