Detect cycle in an undirected graph

Last Updated : 4 Nov, 2025

Given an adjacency list adj[][] representing an undirected graph, determine whether the graph contains a cycle/loop or not.
A cycle is a path that starts and ends at the same vertex without repeating any edge.

Examples:

Input: adj[][]= [[1, 2], [0, 2], [0, 1, 3], [2]]

file

Output: true
Explanation: There is a cycle 0 → 2 → 1 → 0

Input: adj[][] = [[1], [0, 2], [1, 3], [2]]

file

Output: false
Explanation: There is no cycle in the given graph.

Try it on GfG Practice
redirect icon

[Approach 1] Using Depth First Search - O(V+E) Time and O(V) Space

The idea is to use Depth First Search (DFS). When we start a DFS from a node, we visit all its connected neighbors one by one. If during this traversal, we reach a node that has already been visited before, it indicates that there might be a cycle, since we’ve come back to a previously explored vertex.
However, there’s one important catch.
In an undirected graph, every edge is bidirectional. That means, if there’s an edge from u → v, then there’s also an edge from v → u.
So, while performing DFS, from u, we go to v. From v, we again see u as one of its neighbors. Since u is already visited, it might look like a cycle — but it’s not.

To avoid this issue, we keep track of the parent node — the node from which we reached the current node in DFS. When we move from u to v, we mark u as the parent of v. Now, while checking the neighbors of v, If a neighbor is not visited, we continue DFS for that node.If a neighbor is already visited and not equal to the parent, it means there’s another path that leads back to this node — and hence, a cycle exists.

C++
//Driver Code Starts
#include <iostream>
#include<vector>
using namespace std;

//Driver Code Ends

bool dfs(int v, vector<vector<int>> &adj, vector<bool> &visited, int parent)
{
    // Mark the current node as visited
    visited[v] = true;

    // Recur for all the vertices adjacent to this vertex
    for (int i : adj[v])
    {
        // If an adjacent vertex is not visited, 
        //then recur for that adjacent
        if (!visited[i])
        {
            if (dfs(i, adj, visited, v))
                return true;
        }
        
        // If an adjacent vertex is visited and is not
        //parent of current vertex,
        // then there exists a cycle in the graph.
        else if (i != parent)
            return true;
    }

    return false;
}

// Returns true if the graph contains a cycle, else false.
bool isCycle(vector<vector<int>> &adj)
{
    int V= adj.size();
    // Mark all the vertices as not visited
    vector<bool> visited(V, false);

    for (int u = 0; u < V; u++)
    {
        if (!visited[u])
        {
            if (dfs(u, adj, visited, -1))
                return true;
        }
    }

    return false;
}

//Driver Code Starts

int main()
{
    vector<vector<int>> adj = {{1, 2}, {0, 2}, {0, 1, 3}, {2}};
    isCycle(adj) ? cout << "true" : cout << "false";

    return 0;

}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;

public class GFG {

//Driver Code Ends

    static boolean dfs(int v, ArrayList<ArrayList<Integer>> adj, boolean[] visited, int parent) {
        // Mark the current node as visited
        visited[v] = true;

        // Recur for all the vertices adjacent to this vertex
        for (int neighbor : adj.get(v)) {

            // If an adjacent vertex is not visited, 
            // then recur for that adjacent
            if (!visited[neighbor]) {
                if (dfs(neighbor, adj, visited, v))
                    return true;
            }
            // If an adjacent vertex is visited and is not
            // parent of current vertex,
            // then there exists a cycle in the graph.
            else if (neighbor != parent)
                return true;
        }

        return false;
    }

    // Returns true if the graph contains a cycle, else false.
    static boolean isCycle(ArrayList<ArrayList<Integer>> adj) {
        int V = adj.size();
        
        // Mark all the vertices as not visited
        boolean[] visited = new boolean[V];

        for (int u = 0; u < V; u++) {
            if (!visited[u]) {
                if (dfs(u, adj, visited, -1))
                    return true;
            }
        }

        return false;
    }

//Driver Code Starts
     
     // Function to add an edge to the adjacency list
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {
        adj.get(u).add(v);
        adj.get(v).add(u); 
    }

    public static void main(String[] args) {
        int V = 4;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < V; i++)
            adj.add(new ArrayList<>());

        // Add edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);

        System.out.print(isCycle(adj) ? "true" : "false");
    }
}

//Driver Code Ends
Python
def dfs(v, adj, visited, parent):
    
    # Mark the current node as visited
    visited[v] = True

    # Recur for all the vertices adjacent to this vertex
    for neighbor in adj[v]:
        
        # If an adjacent vertex is not visited, 
        # then recur for that adjacent
        if not visited[neighbor]:
            if dfs(neighbor, adj, visited, v):
                return True
                
        # If an adjacent vertex is visited and is not
        # parent of current vertex,
        # then there exists a cycle in the graph.
        elif neighbor != parent:
            return True

    return False

# Returns true if the graph contains a cycle, else false.
def isCycle(adj):
    V = len(adj)
    # Mark all the vertices as not visited
    visited = [False] * V

    for u in range(V):
        if not visited[u]:
            if dfs(u, adj, visited, -1):
                return True

    return False


#Driver Code Starts
if __name__ == "__main__":
    adj = [[1, 2],[0, 2],[0, 1, 3],[2]]

    print("true" if isCycle(adj) else "false")

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG
{
//Driver Code Ends

     // Function to add an edge to the adjacency list
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u); 
    }
    
    static bool dfs(int v, List<List<int>> adj, bool[] visited, int parent)
    {
        // Mark the current node as visited
        visited[v] = true;

        // Recur for all the vertices adjacent to this vertex
        foreach (int neighbor in adj[v])
        {
            // If an adjacent vertex is not visited, 
            // then recur for that adjacent
            if (!visited[neighbor])
            {
                if (dfs(neighbor, adj, visited, v))
                    return true;
            }
            // If an adjacent vertex is visited and is not
            // parent of current vertex,
            // then there exists a cycle in the graph.
            else if (neighbor != parent)
                return true;
        }

        return false;
    }

    // Returns true if the graph contains a cycle, else false.
    static bool isCycle(List<List<int>> adj)
    {
        int V = adj.Count;
        // Mark all the vertices as not visited
        bool[] visited = new bool[V];

        for (int u = 0; u < V; u++)
        {
            if (!visited[u])
            {
                if (dfs(u, adj, visited, -1))
                    return true;
            }
        }

        return false;
    }

//Driver Code Starts

    static void Main()
    {
        int V = 4;
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Add edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);

        Console.Write(isCycle(adj) ? "true" : "false");
    }
}

//Driver Code Ends
JavaScript
function dfs(v, adj, visited, parent) {
    // Mark the current node as visited
    visited[v] = true;

    let V = adj.length;

    // Recur for all the vertices adjacent to this vertex
    for (let i = 0; i < V; i++) {
        if (adj[v][i] !== -1) {
            let neighbor = i;

            // If an adjacent vertex is not visited, 
            // then recur for that adjacent
            if (!visited[neighbor]) {
                if (dfs(neighbor, adj, visited, v))
                    return true;
            }
            // If an adjacent vertex is visited and is not
            // parent of current vertex,
            // then there exists a cycle in the graph.
            else if (neighbor !== parent)
                return true;
        }
    }

    return false;
}

// Returns true if the graph contains a cycle, else false.
function isCycle(adj) {
    let V = adj.length;
    // Mark all the vertices as not visited
    let visited = Array(V).fill(false);

    for (let u = 0; u < V; u++) {
        if (!visited[u]) {
            if (dfs(u, adj, visited, -1))
                return true;
        }
    }

    return false;
}


//Driver Code Starts
// Driver code
let adj = [[1, 2],[0, 2],[0, 1, 3],[2]];

console.log(isCycle(adj) ? "true" : "false");
//Driver Code Ends

Output
true

[Approach 2] Using Breadth First Search - O(V+E) Time and O(V) Space

The idea is quite similar to DFS-based cycle detection, but here we use Breadth First Search (BFS) instead of recursion. BFS explores the graph level by level, ensuring that each node is visited in the shortest possible way. It also helps avoid deep recursion calls, making it more memory-efficient for large graphs.

In BFS, we also maintain a visited array to mark nodes that have been explored and a parent tracker to remember from which node we reached the current one.
If during traversal we encounter a node that is already visited and is not the parent of the current node, it means we’ve found a cycle in the graph.

C++
//Driver Code Starts
#include <iostream>
#include<vector>
#include<queue>
using namespace std;
//Driver Code Ends


// Function to perform BFS from node 'start' to detect cycle
bool bfs(int start, vector<vector<int>>& adj, vector<bool>& visited) {
    
    // Queue stores {current node, parent node}
    queue<pair<int, int>> q;
     
     // Start node has no parent
    q.push({start, -1});
    visited[start] = true;

    while (!q.empty()) {
        int node = q.front().first;
        int parent = q.front().second;
        q.pop();

        // Traverse all neighbors of current node
        for (int neighbor : adj[node]) {

            // If neighbor is not visited, mark it visited and push to queue
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                q.push({neighbor, node});
            } 
            // If neighbor is visited and not parent, a cycle is detected
            else if (neighbor != parent) {
                return true;
            }
        }
    }
    
    // No cycle found starting from this node
    return false; 
}

// Function to check if the undirected graph contains a cycle
bool isCycle(vector<vector<int>>& adj) {
    
    int V= adj.size();
    
    // Keep track of visited vertices
    vector<bool> visited(V, false); 

    // Perform BFS from every unvisited node
    for (int i = 0; i < V; i++) {
        if (!visited[i]) {
            
            // If BFS finds a cycle
            if (bfs(i, adj, visited)) { 
                return true;
            }
        }
    }
    
    // If no cycle is found in any component
    return false;
}


//Driver Code Starts
int main() {
    vector<vector<int>> adj = {{1, 2}, {0, 2}, {0, 1, 3}, {2}};
    isCycle(adj) ? cout << "true" : cout << "false";

    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class GFG {
//Driver Code Ends


    // Function to perform BFS from node 'start' to detect cycle
    static boolean bfs(int start, ArrayList<ArrayList<Integer>> adj, boolean[] visited) {
        
        // Queue stores {current node, parent node}
        Queue<int[]> q = new LinkedList<>();
         
        // Start node has no parent
        q.add(new int[]{start, -1});
        visited[start] = true;

        while (!q.isEmpty()) {
            int node = q.peek()[0];
            int parent = q.peek()[1];
            q.poll();

            // Traverse all neighbors of current node
            for (int neighbor : adj.get(node)) {

                // If neighbor is not visited, mark it visited and push to queue
                if (!visited[neighbor]) {
                    visited[neighbor] = true;
                    q.add(new int[]{neighbor, node});
                } 
                // If neighbor is visited and not parent, a cycle is detected
                else if (neighbor != parent) {
                    return true;
                }
            }
        }
        
        // No cycle found starting from this node
        return false; 
    }

    // Function to check if the undirected graph contains a cycle
    static boolean isCycle(ArrayList<ArrayList<Integer>> adj) {
        
        int V= adj.size();
        
        // Keep track of visited vertices
        boolean[] visited = new boolean[V]; 

        // Perform BFS from every unvisited node
        for (int i = 0; i < V; i++) {
            if (!visited[i]) {
                
                // If BFS finds a cycle
                if (bfs(i, adj, visited)) { 
                    return true;
                }
            }
        }
        
        // If no cycle is found in any component
        return false;
    }
    

//Driver Code Starts
    // Function to add an edge to the adjacency list
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {
        adj.get(u).add(v);
        adj.get(v).add(u); 
    }


    public static void main(String[] args) {
        int V = 4;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < V; i++) {
            adj.add(new ArrayList<>());
        }

        // Add edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);

        System.out.println(isCycle(adj) ? "true" : "false");
    }
}

//Driver Code Ends
Python
from collections import deque

# Function to perform BFS from node 'start' to detect cycle
def bfs(start, adj, visited):
    
    # Queue stores [current node, parent node]
    q = deque()
     
     # Start node has no parent
    q.append([start, -1])
    visited[start] = True

    while q:
        node = q[0][0]
        parent = q[0][1]
        q.popleft()

        # Traverse all neighbors of current node
        for neighbor in adj[node]:

            # If neighbor is not visited, mark it visited and push to queue
            if not visited[neighbor]:
                visited[neighbor] = True
                q.append([neighbor, node])
            # If neighbor is visited and not parent, a cycle is detected
            elif neighbor != parent:
                return True
    
    # No cycle found starting from this node
    return False

# Function to check if the undirected graph contains a cycle
def isCycle(adj):
    
    V = len(adj)
    
    # Keep track of visited vertices
    visited = [False] * V

    # Perform BFS from every unvisited node
    for i in range(V):
        if not visited[i]:
            
            # If BFS finds a cycle
            if bfs(i, adj, visited):
                return True
    
    # If no cycle is found in any component
    return False



#Driver Code Starts

if __name__ == "__main__":
    adj = [[1, 2],[0, 2],[0, 1, 3],[2]]
    
    print("true" if isCycle(adj) else "false")

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG
{
//Driver Code Ends

    // Function to perform BFS from node 'start' to detect cycle
    static bool bfs(int start, List<List<int>> adj, bool[] visited)
    {
        // Queue stores {current node, parent node}
        Queue<int[]> q = new Queue<int[]>();

        // Start node has no parent
        q.Enqueue(new int[] { start, -1 });
        visited[start] = true;

        while (q.Count > 0)
        {
            int node = q.Peek()[0];
            int parent = q.Peek()[1];
            q.Dequeue();

            // Traverse all neighbors of current node
            foreach (int neighbor in adj[node])
            {
                // If neighbor is not visited, mark it visited and push to queue
                if (!visited[neighbor])
                {
                    visited[neighbor] = true;
                    q.Enqueue(new int[] { neighbor, node });
                }
                // If neighbor is visited and not parent, a cycle is detected
                else if (neighbor != parent)
                {
                    return true;
                }
            }
        }

        // No cycle found starting from this node
        return false;
    }

    // Function to check if the undirected graph contains a cycle
    static bool isCycle(List<List<int>> adj)
    {
        int V = adj.Count;

        // Keep track of visited vertices
        bool[] visited = new bool[V];

        // Perform BFS from every unvisited node
        for (int i = 0; i < V; i++)
        {
            if (!visited[i])
            {
                // If BFS finds a cycle
                if (bfs(i, adj, visited))
                {
                    return true;
                }
            }
        }

        // If no cycle is found in any component
        return false;
    }
    

//Driver Code Starts
     // Function to add an edge to the adjacency list
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u); 
    }

    static void Main()
    {
        int V = 4;
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Add edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);
        addEdge(adj, 2, 3);

        Console.WriteLine(isCycle(adj) ? "true" : "false");
    }
}

//Driver Code Ends
JavaScript
const Deque = require("denque");

// Function to perform BFS from node 'start' to detect cycle
function bfs(start, adj, visited) {

    // Queue stores [current node, parent node]
    let q = new Deque();

    // Start node has no parent
    q.push([start, -1]);
    visited[start] = true;

    while (q.length > 0) {
        let [node, parent] = q.shift(); // pop from front

        // Traverse all neighbors of current node
        for (let neighbor of adj[node]) {

            // If neighbor is not visited, mark visited and enqueue
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                q.push([neighbor, node]);
            }
            // If neighbor is visited and not the parent, cycle found
            else if (neighbor !== parent) {
                return true;
            }
        }
    }

    // No cycle found starting from this node
    return false;
}

// Function to check if the undirected graph contains a cycle
function isCycle(adj) {
    let V = adj.length;
    let visited = Array(V).fill(false);

    // Perform BFS from every unvisited node
    for (let i = 0; i < V; i++) {
        if (!visited[i]) {
            if (bfs(i, adj, visited)) {
                return true;
            }
        }
    }

    // No cycle found in any component
    return false;
}


// Example usage
//Driver Code Starts
let adj = [[1, 2],[0, 2],[0, 1, 3],[2]];

console.log(isCycle(adj) ? "true" : "false");

//Driver Code Ends


Related Articles:

Comment