Open In App

Dynamic Disjoint Set Data Structure for large range values

Improve
Improve
Like Article
Like
Save
Share
Report

Prerequisites: 

Disjoint Set data structure is used to keep track of a set of elements partitioned into a number of disjoint (non-overlapping) subsets.

In this article, we will learn about constructing the same Data Structure dynamically. This data structure basically helps in situations where we cannot simply use arrays for creating disjoint sets because of large inputs of order 109.

To illustrate this, consider the following problem. We need to find the total number of connected components in the Graph when the total Number of Vertices can be up to 10^9.

Examples:  

Input : Edges : { { 1, 2 }, 
                  { 2, 3 }, 
                  { 4, 5 } }
Output : 2
Explanation: {1, 2, 3} forms a component and 
{4, 5} forms another component.

The idea to solve this problem is, we will maintain two hash tables (implemented using unordered_maps in C++). One for parent and other for degree. Parent[V] will give the parent of the component which the Vertex V is part of and Degree will give the number of vertices in that component.

Initially, both Parent and Degree will be empty. We will keep inserting vertices to the maps as sequentially.
See the code and the explanation simultaneously for a better understanding. Below are the methods used in the code to solve the above problem:

  1. getParent(V): This method will give the parent of the vertex V. Here we recursively find the parent of the vertex V( see code), meanwhile we assign all the vertex in that component to have the same parent.( In a disjoint set data structure all the vertex in the same component have the same parent.)
  2. Union(): When we add an edge and the two vertexes are of different components we call the Union() method to join both components. Here the parent of the component formed after joining both components will be the parent of the component among the two which had more vertexes before the union. The degree of the new component is updated accordingly.
  3. getTotalComponent(): Vertex in the same component will have the same parent. 
    We use unordered_set (STL) to count the total number of components. As we have maintained the Data Structure as Dynamic, there can be any vertex that has not been added to any of the components hence they are different components alone. So the total number of components will be given by,
Total no of Component =  Total Vertices - Number of Vertices
                         in parent (Map)  + Number of Component 
                         formed from the Vertexes inserted 
                         in the graph.

Below is the implementation of the above idea: 

C++




// Dynamic Disjoint Set Data Structure
// Union-Find
 
#include <bits/stdc++.h>
using namespace std;
 
int N;
int Edges[3][2];
 
// Dynamic Disjoint Set Data Structure
struct DynamicDisjointSetDS {
 
    // We will add the vertex to the edge
    // only when it is asked to i.e. maintain
    // a dynamic DS.
    unordered_map<int, int> parent, degree;
 
    // Total number of Vertex in the Graph
    int N;
 
    // Constructor
    DynamicDisjointSetDS(int n)
    {
        N = n;
    }
 
    // Get Parent of vertex V
    int getParent(int vertex)
    {
 
        // If the vertex is already inserted
        // in the graph
        if (parent.find(vertex) != parent.end()) {
 
            if (parent[vertex] != vertex) {
                parent[vertex] =
                    getParent(parent[vertex]);
                return parent[vertex];
            }
        }
 
        // if the vertex is operated for the first
        // time
        else {
 
            // insert the vertex and assign its
            // parent to itself
            parent.insert(make_pair(vertex, vertex));
 
            // Degree of the vertex
            degree.insert(make_pair(vertex, 1));
        }
 
        return vertex;
    }
 
    // Union by Rank
    void Union(int vertexA, int vertexB)
    {
        // Parent of Vertex A
        int x = getParent(vertexA);
 
        // Parent of Vertex B
        int y = getParent(vertexB);
 
        // if both have same parent
        // Do Nothing
        if (x == y)
            return;
 
        // Merging the component
        // Assigning the parent of smaller Component
        // as the parent of the bigger Component.
        if (degree[x] > degree[y]) {
            parent[y] = x;
            degree[x] = degree[x] + degree[y];
        }
        else {
            parent[x] = y;
            degree[y] = degree[y] + degree[x];
        }
    }
 
    // Count total Component in the Graph
    int GetTotalComponent()
    {
        // To count the total Component formed
        // from the inserted vertex in the Graph
        unordered_set<int> total;
 
        // Iterate through the parent
        for (auto itr = parent.begin();
            itr != parent.end(); itr++) {
 
            // Add the parent of each Vertex
            // to the set
            total.insert(getParent(itr->first));
        }
 
        // Total Component = Total Vertexes -
        // Number of Vertex in the parent +
        // Number of Component formed from
        // the Vertexes inserted in the Graph
        return N - parent.size() + total.size();
    }
};
 
// Solve
void Solve()
{
 
    // Declaring the Dynamic Disjoint Set DS
    DynamicDisjointSetDS dsu(N);
 
    // Traversing through the Edges
    for (int i = 0; i < 3; i++) {
 
        // If the Vertexes in the Edges
        // have same parent do nothing
        if (dsu.getParent(Edges[i][0]) ==
            dsu.getParent(Edges[i][1])) {
            continue;
        }
 
        // else Do Union of both the Components.
        else {
            dsu.Union(Edges[i][0], Edges[i][1]);
        }
    }
 
    // Get total Components
    cout << dsu.GetTotalComponent();
}
 
// Driver Code
int main()
{
    // Total Number of Vertexes
    N = 5;
     
    /* Edges
    * 1 <--> 2
    * 2 <--> 3
    * 4 <--> 5 */
 
    Edges[0][0] = 1;
    Edges[0][1] = 2;
    Edges[1][0] = 2;
    Edges[1][1] = 3;
    Edges[2][0] = 4;
    Edges[2][1] = 3;
 
    // Solve
    Solve();
 
    return 0;
}


Java




// Dynamic Disjoint Set Data Structure
// Union-Find
import java.util.*;
 
// Dynamic Disjoint Set Data Structure
class DynamicDisjointSetDS {
    // We will add the vertex to the edge
    // only when it is asked to i.e. maintain
    // a dynamic DS.
    Map<Integer, Integer> parent, degree;
 
    // Total number of Vertex in the Graph
    int N;
 
    // Constructor
    DynamicDisjointSetDS(int n)
    {
        N = n;
        parent = new HashMap<>();
        degree = new HashMap<>();
    }
 
    // Get Parent of vertex V
    int getParent(int vertex)
    {
        // If the vertex is already inserted
        // in the graph
        if (parent.containsKey(vertex)) {
            if (parent.get(vertex) != vertex) {
                parent.put(vertex,
                           getParent(parent.get(vertex)));
                return parent.get(vertex);
            }
        }
 
        // if the vertex is operated for the first
        // time
        else {
            // insert the vertex and assign its
            // parent to itself
            parent.put(vertex, vertex);
 
            // Degree of the vertex
            degree.put(vertex, 1);
        }
        return vertex;
    }
 
    // Union by Rank
    void union(int vertexA, int vertexB)
    {
        // Parent of Vertex A
        int x = getParent(vertexA);
 
        // Parent of Vertex B
        int y = getParent(vertexB);
 
        // if both have same parent
        // Do Nothing
        if (x == y) {
            return;
        }
 
        // Merging the component
        // Assigning the parent of smaller Component
        // as the parent of the bigger Component.
        if (degree.get(x) > degree.get(y)) {
            parent.put(y, x);
            degree.put(x, degree.get(x) + degree.get(y));
        }
        else {
            parent.put(x, y);
            degree.put(y, degree.get(y) + degree.get(x));
        }
    }
 
    // Count total Component in the Graph
    int getTotalComponent()
    {
        // To count the total Component formed
        // from the inserted vertex in the Graph
        Set<Integer> total = new HashSet<>();
 
        // Iterate through the parent
        for (Map.Entry<Integer, Integer> entry :
             parent.entrySet()) {
 
            // Add the parent of each Vertex
            // to the set
            total.add(getParent(entry.getKey()));
        }
 
        // Total Component = Total Vertexes -
        // Number of Vertex in the parent +
        // Number of Component formed from
        // the Vertexes inserted in the Graph
        return N - parent.size() + total.size();
    }
}
 
// Driver Code
public class Main {
    public static void main(String[] args)
    {
        // Total Number of Vertexes
        int N = 5;
 
        /* Edges
         * 1 <--> 2
         * 2 <--> 3
         * 4 <--> 5 */
        int[][] Edges = { { 1, 2 }, { 2, 3 }, { 4, 3 } };
 
        DynamicDisjointSetDS dsu
            = new DynamicDisjointSetDS(N);
        for (int i = 0; i < 3; i++) {
            if (dsu.getParent(Edges[i][0])
                == dsu.getParent(Edges[i][1])) {
                continue;
            }
            else {
                dsu.union(Edges[i][0], Edges[i][1]);
            }
        }
        System.out.println(dsu.getTotalComponent());
    }
}


Python3




# Dynamic Disjoint Set Data Structure
# Union-Find
 
# Dynamic Disjoint Set Data Structure
class DynamicDisjointSetDS:
 
    # Constructor
    def __init__(self, n):
         
        # Total number of Vertex in the Graph
        self.N = n
         
        # We will add the vertex to the edge
        # only when it is asked to i.e. maintain
        # a dynamic DS.
        self.parent = {}
        self.degree = {}
 
    # Get Parent of vertex V
    def getParent(self, vertex):
     
        # If the vertex is already inserted
        # in the graph
        if vertex in self.parent:
 
            if self.parent[vertex] != vertex:
                self.parent[vertex] = \
                    self.getParent(self.parent[vertex])
                     
                return self.parent[vertex]
 
        # if the vertex is operated
        # for the first time
        else:
 
            # insert the vertex and assign
            # its parent to itself
            self.parent[vertex] = vertex
 
            # Degree of the vertex
            self.degree[vertex] = 1
         
        return vertex
     
    # Union by Rank
    def Union(self, vertexA, vertexB):
     
        # Parent of Vertex A
        x = self.getParent(vertexA)
 
        # Parent of Vertex B
        y = self.getParent(vertexB)
 
        # if both have same parent
        # Do Nothing
        if x == y:
            return
 
        # Merging the component
        # Assigning the parent of smaller Component
        # as the parent of the bigger Component.
        if self.degree[x] > self.degree[y]:
            self.parent[y] = x
            self.degree[x] = (self.degree[x] +
                              self.degree[y])
         
        else:
            self.parent[x] = y
            self.degree[y] = (self.degree[y] +
                              self.degree[x])
         
    # Count total Component in the Graph
    def GetTotalComponent(self):
     
        # To count the total Component formed
        # from the inserted vertex in the Graph
        total = set()
 
        # Iterate through the parent
        for itr in self.parent:
 
            # Add the parent of each Vertex
            # to the set
            total.add(self.getParent(itr))
         
        # Total Component = Total Vertexes -
        # Number of Vertex in the parent +
        # Number of Component formed from
        # the Vertexes inserted in the Graph
        return self.N - len(self.parent) + len(total)
 
# Solve
def Solve(N):
 
    # Declaring the Dynamic Disjoint Set DS
    dsu = DynamicDisjointSetDS(N)
 
    # Traversing through the Edges
    for i in range(0, 3):
 
        # If the Vertexes in the Edges
        # have same parent do nothing
        if (dsu.getParent(Edges[i][0]) ==
            dsu.getParent(Edges[i][1])):
            continue
 
        # else Do Union of both the Components.
        else:
            dsu.Union(Edges[i][0], Edges[i][1])
 
    # Get total Components
    print(dsu.GetTotalComponent())
 
# Driver Code
if __name__ == "__main__":
 
    # Total Number of Vertexes
    N = 5
    Edges = [[1, 2], [2, 3], [4, 3]]
 
    # Solve
    Solve(N)
 
# This code is contributed by
# Rituraj Jain


C#




// Dynamic Disjoint Set Data Structure
// Union-Find
using System;
using System.Collections.Generic;
 
public class GFG {
    static int N;
    static int[, ] Edges = new int[3, 2];
 
    // Dynamic Disjoint Set Data Structure
    public class DynamicDisjointSetDS {
 
        // We will add the vertex to the edge
        // only when it is asked to i.e. maintain
        // a dynamic DS.
        Dictionary<int, int> parent
            = new Dictionary<int, int>();
        Dictionary<int, int> degree
            = new Dictionary<int, int>();
 
        // Total number of Vertex in the Graph
        int N;
 
        // Constructor
        public DynamicDisjointSetDS(int n) { N = n; }
 
        // Get Parent of vertex V
        public int GetParent(int vertex)
        {
 
            // If the vertex is already inserted
            // in the graph
            if (parent.ContainsKey(vertex)) {
                if (parent[vertex] != vertex) {
                    parent[vertex]
                        = GetParent(parent[vertex]);
                    return parent[vertex];
                }
            }
 
            // if the vertex is operated for the first
            // time
            else {
 
                // insert the vertex and assign its
                // parent to itself
                parent[vertex] = vertex;
 
                // Degree of the vertex
                degree[vertex] = 1;
            }
            return vertex;
        }
 
        // Union by Rank
        public void Union(int vertexA, int vertexB)
        {
 
            // Parent of Vertex A
            int x = GetParent(vertexA);
 
            // Parent of Vertex B
            int y = GetParent(vertexB);
 
            // if both have same parent
            // Do Nothing
            if (x == y)
                return;
 
            // Merging the component
            // Assigning the parent of smaller Component
            // as the parent of the bigger Component.
            if (degree[x] > degree[y]) {
                parent[y] = x;
                degree[x] += degree[y];
            }
            else {
                parent[x] = y;
                degree[y] += degree[x];
            }
        }
 
        // Count total Component in the Graph
        public int GetTotalComponent()
        {
 
            // To count the total Component formed
            // from the inserted vertex in the Graph
            HashSet<int> total = new HashSet<int>();
 
            // Iterate through the parent
            foreach(int key in new List<int>(parent.Keys))
            {
 
                // Add the parent of each Vertex
                // to the set
                total.Add(GetParent(key));
            }
 
            // Total Component = Total Vertexes -
            // Number of Vertex in the parent +
            // Number of Component formed from
            // the Vertexes inserted in the Graph
            return N - parent.Count + total.Count;
        }
    }
 
    // Solve
    public static void Solve()
    {
 
        // Declaring the Dynamic Disjoint Set DS
        DynamicDisjointSetDS dsu
            = new DynamicDisjointSetDS(N);
 
        // Traversing through the Edges
        for (int i = 0; i < 3; i++) {
 
            // If the Vertexes in the Edges
            // have same parent do nothing
            if (dsu.GetParent(Edges[i, 0])
                == dsu.GetParent(Edges[i, 1])) {
                continue;
            }
 
            // else Do Union of both the Components.
            else {
                dsu.Union(Edges[i, 0], Edges[i, 1]);
            }
        }
 
        // Get total Components
        Console.WriteLine(dsu.GetTotalComponent());
    }
 
    // Driver Code
    public static void Main()
    {
 
        // Total Number of Vertexes
        N = 5;
 
        /* Edges
         * 1 <--> 2
         * 2 <--> 3
         * 4 <--> 5 */
 
        Edges[0, 0] = 1;
        Edges[0, 1] = 2;
        Edges[1, 0] = 2;
        Edges[1, 1] = 3;
        Edges[2, 0] = 4;
        Edges[2, 1] = 3;
 
        // Solve
        Solve();
    }
}
// This code is contributed by prasad264


Javascript




// Dynamic Disjoint Set Data Structure
// Union-Find
 
const N = 5;
const Edges = [[1, 2], [2, 3], [4, 5]];
 
// Dynamic Disjoint Set Data Structure
class DynamicDisjointSetDS {
  // Constructor
  constructor(n) {
    this.N = n;
    this.parent = new Map();
    this.degree = new Map();
  }
 
  // Get Parent of vertex V
  getParent(vertex) {
    // If the vertex is already inserted
    // in the graph
    if (this.parent.has(vertex)) {
      if (this.parent.get(vertex) !== vertex) {
        this.parent.set(vertex, this.getParent(this.parent.get(vertex)));
        return this.parent.get(vertex);
      }
    }
    // if the vertex is operated for the first
    // time
    else {
     
      // insert the vertex and assign its
      // parent to itself
      this.parent.set(vertex, vertex);
       
      // Degree of the vertex
      this.degree.set(vertex, 1);
    }
     
    return vertex;
  }
 
  // Union by Rank
  Union(vertexA, vertexB) {
    // Parent of Vertex A
    const x = this.getParent(vertexA);
     
    // Parent of Vertex B
    const y = this.getParent(vertexB);
     
    // if both have same parent
    // Do Nothing
    if (x === y) {
      return;
    }
     
    // Merging the component
    // Assigning the parent of smaller Component
    // as the parent of the bigger Component.
    if (this.degree.get(x) > this.degree.get(y)) {
      this.parent.set(y, x);
      this.degree.set(x, this.degree.get(x) + this.degree.get(y));
    } else {
      this.parent.set(x, y);
      this.degree.set(y, this.degree.get(y) + this.degree.get(x));
    }
  }
 
  // Count total Component in the Graph
  GetTotalComponent() {
    // To count the total Component formed
    // from the inserted vertex in the Graph
    const total = new Set();
     
    // Iterate through the parent
    for (const [key, value] of this.parent) {
     
      // Add the parent of each Vertex
      // to the set
      total.add(this.getParent(key));
    }
     
    // Total Component = Total Vertexes -
    // Number of Vertex in the parent +
    // Number of Component formed from
    // the Vertexes inserted in the Graph
    return this.N - this.parent.size + total.size;
  }
}
 
// Solve
function solve() {
 
  // Declaring the Dynamic Disjoint Set DS
  const dsu = new DynamicDisjointSetDS(N);
   
  // Traversing through the Edges
  for (let i = 0; i < Edges.length; i++) {
   
    // If the Vertexes in the Edges
    // have same parent do nothing
    if (dsu.getParent(Edges[i][0]) === dsu.getParent(Edges[i][1])) {
      continue;
    }
     
    // else Do Union of both the Components.
    else {
      dsu.Union(Edges[i][0], Edges[i][1]);
    }
  }
   
  // Get total Components
  console.log(dsu.GetTotalComponent());
}
 
// Driver Code
solve();


Output: 

2

Time Complexity: O(E * alpha(N)), where E is the number of edges in the graph, N is the number of vertices in the graph, and alpha is the inverse Ackermann function, which has a value less than 5 for all practical values of N.

Space Complexity: O(N), where N is the total number of vertices in the graph.

Note: If the number of vertices is even larger, we can implement the same code just by changing the data type from int to long.
 



Last Updated : 14 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads