Open In App

Connected Components in an Undirected Graph

Last Updated : 16 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an undirected graph, the task is to return all the connected components in any order. 

Examples:

Input: Consider the following graph

Example of an undirected graph
Example of an undirected graph

Output: [[0, 1, 2], [3, 4]]
Explanation: There are 2 different connected components.
They are {0, 1, 2} and {3, 4}.

Approach 1: Using Depth first search (DFS)

The main idea is to Use DFS to explore each node. If a node hasn’t been visited yet, start a DFS from it. All nodes reached during this traversal belong to the same connected component.

Step by Step implementation:

  • Create an adjacency list from the edge list.
  • Initialize a visited array and mark every node as unvisited initially.
  • Start from any unvisited node and perform a DFS. All nodes reachable from this node will belong to the same connected component.
  • Iterate over all nodes, and for each unvisited node, perform a DFS and store the result.
C++
#include <iostream>
#include <vector>
using namespace std;

// Function to build the adjacency list from edge list
vector<vector<int>> buildGraph(int V, vector<vector<int>>& edges) {
    
    vector<vector<int>> adj(V);

    // Populate the adjacency list from the edge list
    for (auto edge : edges) {
        int u = edge[0];
        int v = edge[1];

        // Add both directions since the graph is undirected
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    return adj;
}

// Function to perform DFS and collect all
// nodes in the current connected component
void dfs(int node, vector<vector<int>>& adj,
         vector<bool>& vis, vector<int>& component) {
    
    // Mark the current node as visited
    vis[node] = true;

    // Add the node to the current component
    component.push_back(node);

    // Traverse all unvisited neighbors
    for (int neighbor : adj[node]) {
        if (!vis[neighbor]) {
            dfs(neighbor, adj, vis, component);
        }
    }
}

// Function to find all connected components 
// in an undirected graph
vector<vector<int>> getComponents(int V, vector<vector<int>>& edges) {
    
    // Create the graph using the adjacency list
    vector<vector<int>> adj = buildGraph(V, edges);

    // Initialize a visited array to keep track of visited nodes
    vector<bool> vis(V, false);

    // This will store all the connected components
    vector<vector<int>> res;

    // Iterate through all nodes
    for (int i = 0; i < V; ++i) {
        // If the node has not been visited, it's a new component
        if (!vis[i]) {
            
            vector<int> component;

            // Perform DFS to collect all nodes in this component
            dfs(i, adj, vis, component);

            // Add the component to the result list
            res.push_back(component);
        }
    }

    // Return the list of all connected components
    return res;
}

int main() {
    // Number of nodes in the graph
    int V = 5;

    // Edge list representing the undirected graph as vector of vectors
    vector<vector<int>> edges = {{0, 1}, {1, 2}, {3, 4}};

    // Get all connected components using the countComponents function
    vector<vector<int>> res = getComponents(V, edges);

    for (const auto& comp : res) {
        
        for (int node : comp) {
            cout << node << " ";
        }
        cout << "\n";
    }

    return 0;
}
Java
import java.util.*;

class GfG {
    
    // Function to build the adjacency list from edge list
    static ArrayList<ArrayList<Integer>> buildGraph(int V, int[][] edges) {
        
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        
        // Initialize the adjacency list with empty lists
        for (int i = 0; i < V; i++) {
            adj.add(new ArrayList<>());
        }

        // Populate the adjacency list from the edge list
        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];

            // Add both directions since the graph is undirected
            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        return adj;
    }

    // Function to perform DFS and collect all 
    // nodes in the current connected component
    static void dfs(int node, ArrayList<ArrayList<Integer>> adj,
                          boolean[] vis, ArrayList<Integer> component) {
                              
        // Mark the current node as visited
        vis[node] = true;

        // Add the node to the current component
        component.add(node);

        // Traverse all unvisited neighbors
        for (int neighbor : adj.get(node)) {
            if (!vis[neighbor]) {
                dfs(neighbor, adj, vis, component);
            }
        }
    }

    // Function to find all connected components
    // in an undirected graph
    static ArrayList<ArrayList<Integer>> getComponents(int V, int[][] edges) {
        
        // Create the graph using the adjacency list
        ArrayList<ArrayList<Integer>> adj = buildGraph(V, edges);

        // Initialize a visited array to keep track of visited nodes
        boolean[] vis = new boolean[V];

        // This will store all the connected components
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();

        // Iterate through all nodes
        for (int i = 0; i < V; i++) {
            
            // If the node has not been visited, it's a new component
            if (!vis[i]) {
                ArrayList<Integer> component = new ArrayList<>();

                // Perform DFS to collect all nodes in this component
                dfs(i, adj, vis, component);

                // Add the component to the result list
                res.add(component);
            }
        }

        return res;
    }

    public static void main(String[] args) {
        
        // Number of nodes in the graph
        int V = 5;

        // Edge list representing the undirected graph as 2D array
        int[][] edges = {
            {0, 1},
            {1, 2},
            {3, 4}
        };

        // Get all connected components using the getComponents function
        ArrayList<ArrayList<Integer>> res = getComponents(V, edges);

        // Print each connected component
        for (ArrayList<Integer> comp : res) {
            for (int node : comp) {
                System.out.print(node + " ");
            }
            System.out.println();
        }
    }
}
Python
def buildGraph(n, edges):
    
    adj = [[] for _ in range(V)]

    # Populate the adjacency list from the edge list
    for edge in edges:
        u, v = edge[0], edge[1]

        # Add both directions since the graph is undirected
        adj[u].append(v)
        adj[v].append(u)

    return adj

def dfs(node, adj, vis, component):
    
    # Mark the current node as visited
    vis[node] = True

    # Add the node to the current component
    component.append(node)

    # Traverse all unvisited neighbors
    for neighbor in adj[node]:
        if not vis[neighbor]:
            dfs(neighbor, adj, vis, component)

def getComponents(V, edges):
    
    # Create the graph using the adjacency list
    adj = buildGraph(V, edges)

    # Initialize a visited array to keep track of visited nodes
    vis = [False] * V

    # This will store all the connected components
    res = []

    # Iterate through all nodes
    for i in range(V):
        
        # If the node has not been visited, it's a new component
        if not vis[i]:
            component = []

            # Perform DFS to collect all nodes in this component
            dfs(i, adj, vis, component)

            # Add the component to the result list
            res.append(component)

    return res

if __name__ == "__main__":
    
    # Number of nodes in the graph
    V = 5

    # Edge list representing the undirected graph as 2D array
    edges = [
        [0, 1],
        [1, 2],
        [3, 4]
    ]

    # Get all connected components using the countComponents function
    res = getComponents(V, edges)

    # Print each connected component
    for comp in res:
        print(" ".join(map(str, comp)))
C#
using System;
using System.Collections.Generic;

class GfG {
    
    // Function to build the adjacency list from edge list
     static List<List<int>> buildGraph(int V, int[,] edges) {
         
        List<List<int>> adj = new List<List<int>>();

        // Initialize the adjacency list with empty lists for each node
        for (int i = 0; i < V; i++) {
            adj.Add(new List<int>());
        }

        // Populate the adjacency list from the edge list
        for (int i = 0; i < edges.GetLength(0); i++) {
            int u = edges[i, 0];
            int v = edges[i, 1];

            // Add both directions since the graph is undirected
            adj[u].Add(v);
            adj[v].Add(u);
        }

        return adj;
    }

    // Function to perform DFS and collect all
    // nodes in the current connected component
     static void dfs(int node, List<List<int>> adj,
                          bool[] vis, List<int> component) {
                              
        // Mark the current node as visited
        vis[node] = true;

        // Add the node to the current component
        component.Add(node);

        // Traverse all unvisited neighbors
        foreach (int neighbor in adj[node]) {
            if (!vis[neighbor]) {
                dfs(neighbor, adj, vis, component);
            }
        }
    }

    // Function to find all connected components in an undirected graph
    public static List<List<int>> getComponents(int V, int[,] edges) {
        
        // Create the graph using the adjacency list
        List<List<int>> adj = buildGraph(V, edges);

        // Initialize a visited array to keep track of visited nodes
        bool[] vis = new bool[V];

        // This will store all the connected components
        List<List<int>> res = new List<List<int>>();

        // Iterate through all nodes
        for (int i = 0; i < V; i++) {
            
            // If the node has not been visited, it's a new component
            if (!vis[i]) {
                List<int> component = new List<int>();

                // Perform DFS to collect all nodes in this component
                dfs(i, adj, vis, component);

                // Add the component to the result list
                res.Add(component);
            }
        }

        return res;
    }

    static void Main() {
        
        // Number of nodes in the graph
        int V = 5;

        // Edge list representing the undirected graph as 2D array
        int[,] edges = {
            {0, 1},
            {1, 2},
            {3, 4}
        };

        // Get all connected components using the countComponents function
        List<List<int>> res = getComponents(V, edges);

        // Print each connected component
        foreach (var comp in res) {
            foreach (int node in comp) {
                Console.Write(node + " ");
            }
            Console.WriteLine();
        }
    }
}
JavaScript
// Function to build the adjacency list from the edge list
function buildGraph(V, edges) {
    
    let adj = Array.from({ length: V }, () => []);

    // Populate the adjacency list from the edge list
    for (let i = 0; i < edges.length; i++) {
        let u = edges[i][0];
        let v = edges[i][1];

        // Add both directions since the graph is undirected
        adj[u].push(v);
        adj[v].push(u);
    }

    return adj;
}

// Function to perform DFS and collect 
// all nodes in the current connected component
function dfs(node, adj, vis, component) {
    
    // Mark the current node as visited
    vis[node] = true;

    // Add the node to the current component
    component.push(node);

    // Traverse all unvisited neighbors
    for (let neighbor of adj[node]) {
        if (!vis[neighbor]) {
            dfs(neighbor, adj, vis, component);
        }
    }
}

// Function to find all connected components in an undirected graph
function getComponents(V, edges) {
    
    // Create the graph using the adjacency list
    let adj = buildGraph(V, edges);

    // Initialize a visited array to keep track of visited nodes
    let vis = new Array(V).fill(false);

    // This will store all the connected components
    let res = [];

    // Iterate through all nodes
    for (let i = 0; i < V; i++) {
        
        // If the node has not been visited, it's a new component
        if (!vis[i]) {
            let component = [];

            // Perform DFS to collect all nodes in this component
            dfs(i, adj, vis, component);

            // Add the component to the result list
            res.push(component);
        }
    }

    return res;
}

// Driver Code 
let V = 5;

// Edge list representing the undirected graph as 2D array
let edges = [
    [0, 1],
    [1, 2],
    [3, 4]
];

// Get all connected components using the countComponents function
let components = getComponents(V, edges);

// Print each connected component
components.forEach(component => {
    console.log(component.join(" "));
});

Output
0 1 2 
3 4 

Time Complexity: O(V + E) where V is the number of vertices and E is the number of edges.
Auxiliary Space: O(V + E)

Approach 2: Using Disjoint Set Union (DSU)

The idea to solve the problem using DSU (Disjoint Set Union) is to initially declare all the nodes as individual subsets and then visit them. When a new unvisited node is encountered, unite it with the underlying subset. In this manner, a single component will be visited in each traversal

Step by Step implementation:

  • Declare an array arr[] of size V, where V is the total number of nodes in the graph.
  • The value at each index i of the array represents the parent of the node i.
  • At the beginning, each node is its own parent. This is the base state where each node is considered an individual subset.
  • Perform Union Operation:
    • When nodes are united, change the parent of one node to the other, ensuring that the sets are merged properly.
    • Each time two nodes are united, their parents are updated accordingly to reflect the new structure of the set.
  • Traverse the Nodes:
    • Go through each node from 0 to V-1.
    • If a node is its own parent (i.e., it is a representative of a set), perform the DSU (find and union) operation starting from that node.
  • Store the result of every component and return it.
C++
#include <bits/stdc++.h>
using namespace std;

// Function to find the root parent of a node with path compression
int findParent(vector<int>& parent, int x) {
    if (parent[x] == x)
        return x;
    return parent[x] = findParent(parent, parent[x]);
}

// Function to unite two subsets
void unionSets(vector<int>& parent, int x, int y) {
    int px = findParent(parent, x);
    int py = findParent(parent, y);
    if (px != py) {
        parent[px] = py;
    }
}

// Function to find all connected components using DSU
vector<vector<int>> getComponents(int V, vector<vector<int>>& edges) {
    
    // Initialize each node as its own parent
    vector<int> parent(V);
    for (int i = 0; i < V; i++) {
        parent[i] = i;
    }

    // Union sets using edge list
    for (auto& edge : edges) {
        unionSets(parent, edge[0], edge[1]);
    }

    // Apply path compression for all nodes
    for (int i = 0; i < V; i++) {
        parent[i] = findParent(parent, i);
    }

    // Group nodes by their root parent
    unordered_map<int, vector<int>> resMap;
    for (int i = 0; i < V; i++) {
        resMap[parent[i]].push_back(i);
    }

    // Collect all components into a result vector
    vector<vector<int>> res;
    for (auto& entry : resMap) {
        res.push_back(entry.second);
    }

    return res;
}

int main() {
    int V = 5;

    // Edge list as vector of vectors
    vector<vector<int>> edges = {
        {0, 1},
        {1, 2},
        {3, 4}
    };

    // Find connected components using DSU
    vector<vector<int>> res = getComponents(V, edges);
    
    for (const auto& comp : res) {
        for (int node : comp) {
            cout << node << " ";
        }
        cout << endl;
    }

    return 0;
}
Java
import java.util.*;

class GfG {

    // Function to find the root parent of a node with path compression
     static int findParent(ArrayList<Integer> parent, int x) {
        if (parent.get(x) == x)
            return x;
        parent.set(x, findParent(parent, parent.get(x))); 
        return parent.get(x);
    }

    // Function to unite two subsets
    static void unionSets(ArrayList<Integer> parent, int x, int y) {
        int px = findParent(parent, x);
        int py = findParent(parent, y);
        if (px != py) {
            parent.set(px, py); 
        }
    }

    // Function to find all connected components using DSU
    static ArrayList<ArrayList<Integer>> getComponents(int V, int[][] edges) {
        
        // Initialize each node as its own parent
        ArrayList<Integer> parent = new ArrayList<>();
        for (int i = 0; i < V; i++) {
            parent.add(i);
        }

        // Union sets using edge list
        for (int[] edge : edges) {
            unionSets(parent, edge[0], edge[1]);
        }

        // Apply path compression for all nodes
        for (int i = 0; i < V; i++) {
            parent.set(i, findParent(parent, i));
        }

        // Group nodes by their root parent
        Map<Integer, ArrayList<Integer>> resMap = new HashMap<>();
        for (int i = 0; i < V; i++) {
            resMap.putIfAbsent(parent.get(i), new ArrayList<>());
            resMap.get(parent.get(i)).add(i);
        }

        // Collect all components into a result list
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        for (Map.Entry<Integer, ArrayList<Integer>> entry : resMap.entrySet()) {
            res.add(entry.getValue());
        }

        return res;
    }

    public static void main(String[] args) {
        int V = 5;

        // Edge list as 2D array
        int[][] edges = {
            {0, 1},
            {1, 2},
            {3, 4}
        };

        // Find connected components using DSU
        ArrayList<ArrayList<Integer>> res = getComponents(V, edges);

        // Print the connected components
        for (ArrayList<Integer> comp : res) {
            for (int node : comp) {
                System.out.print(node + " ");
            }
            System.out.println();
        }
    }
}
Python
# Function to find the root parent of a node with path compression
def findParent(parent, x):
    if parent[x] == x:
        return x
        
    # Path compression
    parent[x] = findParent(parent, parent[x])  
    return parent[x]

# Function to unite two subsets
def unionSets(parent, x, y):
    px = findParent(parent, x)
    py = findParent(parent, y)
    if px != py:
        
        # Union operation
        parent[px] = py  

def getComponents(V, edges):
    
    # Initialize each node as its own parent
    parent = [i for i in range(V)]

    # Union sets using the edge list
    for edge in edges:
        unionSets(parent, edge[0], edge[1])

    # Apply path compression for all nodes
    for i in range(V):
        parent[i] = findParent(parent, i)

    # Group nodes by their root parent
    resMap = {}
    for i in range(V):
        root = parent[i]
        if root not in resMap:
            resMap[root] = []
        resMap[root].append(i)

    # Collect all components into a result list
    res = list(resMap.values())

    return res

if __name__ == "__main__":
    V = 5

    # Edge list as 2D array (list of lists)
    edges = [
        [0, 1],
        [1, 2],
        [3, 4]
    ]

    # Find connected components using DSU
    res = getComponents(V, edges)

    # Print connected components
    for comp in res:
        print(" ".join(map(str, comp)))
C#
using System;
using System.Collections.Generic;

class GfG {
    // Function to find the root parent of a node with path compression
    public static int findParent(List<int> parent, int x) {
        if (parent[x] == x)
            return x;
            
        // Path compression
        parent[x] = findParent(parent, parent[x]); 
        return parent[x];
    }

    // Function to unite two subsets
    public static void unionSets(List<int> parent, int x, int y) {
        int px = findParent(parent, x);
        int py = findParent(parent, y);
        if (px != py) {
            // Union operation
            parent[px] = py; 
        }
    }

    // Function to find all connected components using DSU
    public static List<List<int>> getComponents(int V, int[,] edges) {
        
        // Initialize each node as its own parent
        List<int> parent = new List<int>(V);
        for (int i = 0; i < V; i++) {
            parent.Add(i);
        }

        // Union sets using the edge list
        for (int i = 0; i < edges.GetLength(0); i++) {
            unionSets(parent, edges[i, 0], edges[i, 1]);
        }

        // Apply path compression for all nodes
        for (int i = 0; i < V; i++) {
            parent[i] = findParent(parent, i);
        }

        // Group nodes by their root parent
        Dictionary<int, List<int>> resMap = new Dictionary<int, List<int>>();
        for (int i = 0; i < V; i++) {
            int root = parent[i];
            if (!resMap.ContainsKey(root)) {
                resMap[root] = new List<int>();
            }
            resMap[root].Add(i);
        }

        // Collect all components into a result list
        List<List<int>> res = new List<List<int>>();
        foreach (var entry in resMap) {
            res.Add(entry.Value);
        }

        return res;
    }

    static void Main(string[] args) {
        int V = 5;

        // Edge list as a 2D array
        int[,] edges = {
            {0, 1},
            {1, 2},
            {3, 4}
        };

        // Find connected components using DSU
        List<List<int>> res = getComponents(V, edges);

        // Print connected components
        foreach (var comp in res) {
            foreach (int node in comp) {
                Console.Write(node + " ");
            }
            Console.WriteLine();
        }
    }
}
JavaScript
// Function to find the root parent of a node with path compression
function findParent(parent, x) {
    if (parent[x] === x)
        return x;
        
    // Path compression
    parent[x] = findParent(parent, parent[x]); 
    return parent[x];
}

// Function to unite two subsets
function unionSets(parent, x, y) {
    let px = findParent(parent, x);
    let py = findParent(parent, y);
    if (px !== py) {
        
         // Union operation
        parent[px] = py;
    }
}

function getComponents(V, edges) {
    
    // Initialize each node as its own parent
    let parent = [];
    for (let i = 0; i < V; i++) {
        parent[i] = i;
    }

    // Union sets using the edge list
    for (let i = 0; i < edges.length; i++) {
        unionSets(parent, edges[i][0], edges[i][1]);
    }

    // Apply path compression for all nodes
    for (let i = 0; i < V; i++) {
        parent[i] = findParent(parent, i);
    }

    // Group nodes by their root parent
    let resMap = {};
    for (let i = 0; i < V; i++) {
        let root = parent[i];
        if (!(root in resMap)) {
            resMap[root] = [];
        }
        resMap[root].push(i);
    }

    // Collect all components into a result array
    let res = [];
    for (let key in resMap) {
        res.push(resMap[key]);
    }

    return res;
}

// Driver code
let V = 5;

// Edge list as 2D array
let edges = [
    [0, 1],
    [1, 2],
    [3, 4]
];

// Find connected components using DSU
let res = getComponents(V, edges);

// Print connected components
for (let i = 0; i < res.length; i++) {
    console.log(res[i].join(' '));
}

Output
3 4 
0 1 2 

Time Complexity: O(V+E)
Auxiliary Space: O(V)


Next Article
Article Tags :
Practice Tags :

Similar Reads