Skip to content
Related Articles
Get the best out of our app
GFG App
Open App
geeksforgeeks
Browser
Continue

Related Articles

Disjoint Set Data Structures

Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article

What is a Disjoint set data structure?

Two sets are called disjoint sets if they don’t have any element in common, the intersection of sets is a null set.

A data structure that stores non overlapping or disjoint subset of elements is called disjoint set data structure. The disjoint set data structure supports following operations:

  • Adding new sets to the disjoint set.
  • Merging disjoint sets to a single disjoint set using Union operation.
  • Finding representative of a disjoint set using Find operation.
  • Check if two sets are disjoint or not. 

Consider a situation with a number of persons and the following tasks to be performed on them:

  • Add a new friendship relation, i.e. a person x becomes the friend of another person y i.e adding new element to a set.
  • Find whether individual x is a friend of individual y (direct or indirect friend)

Examples: 

We are given 10 individuals say, a, b, c, d, e, f, g, h, i, j

Following are relationships to be added:
a <-> b  
b <-> d
c <-> f
c <-> i
j <-> e
g <-> j

Given queries like whether a is a friend of d or not. We basically need to create following 4 groups and maintain a quickly accessible connection among group items:
G1 = {a, b, d}
G2 = {c, f, i}
G3 = {e, g, j}
G4 = {h}

Find whether x and y belong to the same group or not, i.e. to find if x and y are direct/indirect friends.

Partitioning the individuals into different sets according to the groups in which they fall. This method is known as a Disjoint set Union which maintains a collection of Disjoint sets and each set is represented by one of its members.

To answer the above question two key points to be considered are:

  • How to Resolve sets? Initially, all elements belong to different sets. After working on the given relations, we select a member as a representative. There can be many ways to select a representative, a simple one is to select with the biggest index.
  • Check if 2 persons are in the same group? If representatives of two individuals are the same, then they’ll become friends.

Data Structures used are: 

Array:

An array of integers is called Parent[]. If we are dealing with N items, i’th element of the array represents the i’th item. More precisely, the i’th element of the Parent[] array is the parent of the i’th item. These relationships create one or more virtual trees.

Tree:

It is a Disjoint set. If two elements are in the same tree, then they are in the same Disjoint set. The root node (or the topmost node) of each tree is called the representative of the set. There is always a single unique representative of each set. A simple rule to identify a representative is if ‘i’ is the representative of a set, then Parent[i] = i. If i is not the representative of his set, then it can be found by traveling up the tree until we find the representative.

Operations:

Find:

Can be implemented by recursively traversing the parent array until we hit a node that is the parent of itself.

C++




// Finds the representative of the set
// that i is an element of
 
#include<bits/stdc++.h>
using namespace std;
 
int find(int i)
 
{
 
    // If i is the parent of itself
    if (parent[i] == i) {
 
        // Then i is the representative of
        // this set
        return i;
    }
    else {
 
        // Else if i is not the parent of
        // itself, then i is not the
        // representative of his set. So we
        // recursively call Find on its parent
        return find(parent[i]);
    }
}
 
// The code is contributed by Nidhi goel


Java




// Finds the representative of the set
// that i is an element of
import java.io.*;
 
class GFG {
 
    static int find(int i)
 
    {
 
        // If i is the parent of itself
        if (parent[i] == i) {
 
            // Then i is the representative of
            // this set
            return i;
        }
        else {
 
            // Else if i is not the parent of
            // itself, then i is not the
            // representative of his set. So we
            // recursively call Find on its parent
            return find(parent[i]);
        }
    }
}
 
// The code is contributed by Nidhi goel


Python3




# Finds the representative of the set
# that i is an element of
 
def find(i):
 
    # If i is the parent of itself
    if (parent[i] == i):
 
        # Then i is the representative of
        # this set
        return i
    else:
 
        # Else if i is not the parent of
        # itself, then i is not the
        # representative of his set. So we
        # recursively call Find on its parent
        return find(parent[i])
 
 # The code is contributed by Nidhi goel


Javascript




<script>
// Finds the representative of the set
// that i is an element of
 
function find(i)
{
 
    // If i is the parent of itself
    if (parent[i] == i) {
 
        // Then i is the representative of
        // this set
        return i;
    }
    else {
 
        // Else if i is not the parent of
        // itself, then i is not the
        // representative of his set. So we
        // recursively call Find on its parent
        return find(parent[i]);
    }
}
// The code is contributed by Nidhi goel
</script>


C#




using System;
 
public class GFG{
 
    // Finds the representative of the set
    // that i is an element of
    public static int find(int i)
    {
 
        // If i is the parent of itself
        if (parent[i] == i) {
 
            // Then i is the representative of
            // this set
            return i;
        }
        else {
 
            // Else if i is not the parent of
            // itself, then i is not the
            // representative of his set. So we
            // recursively call Find on its parent
            return find(parent[i]);
        }
    }
}


Union: 

It takes two elements as input and finds the representatives of their sets using the Find operation, and finally puts either one of the trees (representing the set) under the root node of the other tree, effectively merging the trees and the sets.

C++




// Unites the set that includes i
// and the set that includes j
 
#include <bits/stdc++.h>
using namespace std;
 
void union(int i, int j) {
 
    // Find the representatives
    // (or the root nodes) for the set
    // that includes i
    int irep = this.Find(i),
 
    // And do the same for the set
    // that includes j
    int jrep = this.Find(j);
 
    // Make the parent of i’s representative
    // be j’s  representative effectively
    // moving all of i’s set into j’s set)
    this.Parent[irep] = jrep;
}


Python3




# Unites the set that includes i
# and the set that includes j
 
def union(parent, rank, i, j):
    # Find the representatives
    # (or the root nodes) for the set
    # that includes i
    irep = find(parent, i)
     
    # And do the same for the set
    # that includes j
    jrep = find(parent, j)
     
    # Make the parent of i’s representative
    # be j’s  representative effectively
    # moving all of i’s set into j’s set)
     
    parent[irep] = jrep


Javascript




// JavaScript code for the approach
 
// Unites the set that includes i
// and the set that includes j
function union(parent, rank, i, j)
{
 
// Find the representatives
// (or the root nodes) for the set
// that includes i
let irep = find(parent, i);
 
// And do the same for the set
// that includes j
let jrep = find(parent, j);
 
// Make the parent of i’s representative
// be j’s representative effectively
// moving all of i’s set into j’s set)
 
parent[irep] = jrep;
}


Improvements (Union by Rank and Path Compression):

The efficiency depends heavily on the height of the tree. We need to minimize the height of tree in order to improve efficiency. We can use Path Compression and Union by rank method to do so.

Path Compression (Modifications to Find()):

It speeds up the data structure by compressing the height of the trees. It can be achieved by inserting a small caching mechanism into the Find operation. Take a look at the code for more details:

C++




// Finds the representative of the set that i
// is an element of.
 
#include <bits/stdc++.h>
using namespace std;
 
int find(int i)
{
 
    // If i is the parent of itself
    if (Parent[i] == i) {
 
        // Then i is the representative
        return i;
    }
    else {
 
        // Recursively find the representative.
        int result = find(Parent[i]);
 
        // We cache the result by moving i’s node
        // directly under the representative of this
        // set
        Parent[i] = result;
       
        // And then we return the result
        return result;
     }
}


Java




// Finds the representative of the set that i
// is an element of.
import java.io.*;
import java.util.*;
 
static int find(int i)
{
 
    // If i is the parent of itself
    if (Parent[i] == i) {
 
        // Then i is the representative
        return i;
    }
    else {
 
        // Recursively find the representative.
        int result = find(Parent[i]);
 
        // We cache the result by moving i’s node
        // directly under the representative of this
        // set
        Parent[i] = result;
       
        // And then we return the result
        return result;
     }
}
 
// The code  is contributed by Arushi jindal.


Python3




#  Finds the representative of the set that i
# is an element of.
 
 
def find(i):
 
    # If i is the parent of itself
    if Parent[i] == i:
 
        # Then i is the representative
        return i
    else:
 
        # Recursively find the representative.
        result = find(Parent[i])
 
        # We cache the result by moving i’s node
        # directly under the representative of this
        # set
        Parent[i] = result
       
        # And then we return the result
        return result
 
# The code is contributed by Arushi  Jindal.


C#




using System;
 
// Finds the representative of the set that i
// is an element of.
public static int find(int i)
{
 
    // If i is the parent of itself
    if (Parent[i] == i) {
 
        // Then i is the representative
        return i;
    }
    else {
 
        // Recursively find the representative.
        int result = find(Parent[i]);
 
        // We cache the result by moving i’s node
        // directly under the representative of this
        // set
        Parent[i] = result;
       
        // And then we return the result
        return result;
     }
}
 
// The code is contributed by Arushi Jindal.


Javascript




// Finds the representative of the set that i
// is an element of.
 
 
function find(i)
{
 
    // If i is the parent of itself
    if (Parent[i] == i) {
 
        // Then i is the representative
        return i;
    }
    else {
 
        // Recursively find the representative.
        let result = find(Parent[i]);
 
        // We cache the result by moving i’s node
        // directly under the representative of this
        // set
        Parent[i] = result;
       
        // And then we return the result
        return result;
     }
}
 
// The code is contributed by Arushi  Jindal.


Union by Rank:

First of all, we need a new array of integers called rank[]. The size of this array is the same as the parent array Parent[]. If i is a representative of a set, rank[i] is the height of the tree representing the set. 
Now recall that in the Union operation, it doesn’t matter which of the two trees is moved under the other (see last two image examples above). Now what we want to do is minimize the height of the resulting tree. If we are uniting two trees (or sets), let’s call them left and right, then it all depends on the rank of left and the rank of right

  • If the rank of left is less than the rank of right, then it’s best to move left under right, because that won’t change the rank of right (while moving right under left would increase the height). In the same way, if the rank of right is less than the rank of left, then we should move right under left.
  • If the ranks are equal, it doesn’t matter which tree goes under the other, but the rank of the result will always be one greater than the rank of the trees.
     

C++




// Unites the set that includes i and the set
// that includes j
 
#include <bits/stdc++.h>
using namespace std;
 
void union(int i, int j) {
 
    // Find the representatives (or the root nodes)
    // for the set that includes i
    int irep = this.find(i);
 
    // And do the same for the set that includes j
    int jrep = this.Find(j);
 
    // Elements are in same set, no need to
    // unite anything.
    if (irep == jrep)
        return;
     
      // Get the rank of i’s tree
    irank = Rank[irep],
 
    // Get the rank of j’s tree
    jrank = Rank[jrep];
 
    // If i’s rank is less than j’s rank
    if (irank < jrank) {
 
        // Then move i under j
        this.parent[irep] = jrep;
    }
 
    // Else if j’s rank is less than i’s rank
    else if (jrank < irank) {
 
        // Then move j under i
        this.Parent[jrep] = irep;
    }
 
    // Else if their ranks are the same
    else {
 
        // Then move i under j (doesn’t matter
        // which one goes where)
        this.Parent[irep] = jrep;
 
        // And increment the result tree’s
        // rank by 1
        Rank[jrep]++;
    }
}


C++




// C++ implementation of disjoint set
 
#include <bits/stdc++.h>
using namespace std;
 
class DisjSet {
    int *rank, *parent, n;
 
public:
   
    // Constructor to create and
    // initialize sets of n items
    DisjSet(int n)
    {
        rank = new int[n];
        parent = new int[n];
        this->n = n;
        makeSet();
    }
 
    // Creates n single item sets
    void makeSet()
    {
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }
 
    // Finds set of given item x
    int find(int x)
    {
        // Finds the representative of the set
        // that x is an element of
        if (parent[x] != x) {
 
            // if x is not the parent of itself
            // Then x is not the representative of
            // his set,
            parent[x] = find(parent[x]);
 
            // so we recursively call Find on its parent
            // and move i's node directly under the
            // representative of this set
        }
 
        return parent[x];
    }
 
    // Do union of two sets represented
    // by x and y.
    void Union(int x, int y)
    {
        // Find current sets of x and y
        int xset = find(x);
        int yset = find(y);
 
        // If they are already in same set
        if (xset == yset)
            return;
 
        // Put smaller ranked item under
        // bigger ranked item if ranks are
        // different
        if (rank[xset] < rank[yset]) {
            parent[xset] = yset;
        }
        else if (rank[xset] > rank[yset]) {
            parent[yset] = xset;
        }
 
        // If ranks are same, then increment
        // rank.
        else {
            parent[yset] = xset;
            rank[xset] = rank[xset] + 1;
        }
    }
};
 
// Driver Code
int main()
{
   
      // Function Call
    DisjSet obj(5);
    obj.Union(0, 2);
    obj.Union(4, 2);
    obj.Union(3, 1);
   
    if (obj.find(4) == obj.find(0))
        cout << "Yes\n";
    else
        cout << "No\n";
    if (obj.find(1) == obj.find(0))
        cout << "Yes\n";
    else
        cout << "No\n";
 
    return 0;
}


Java




// A Java program to implement Disjoint Set Data
// Structure.
import java.io.*;
import java.util.*;
 
class DisjointUnionSets {
    int[] rank, parent;
    int n;
 
    // Constructor
    public DisjointUnionSets(int n)
    {
        rank = new int[n];
        parent = new int[n];
        this.n = n;
        makeSet();
    }
 
    // Creates n sets with single item in each
    void makeSet()
    {
        for (int i = 0; i < n; i++) {
            // Initially, all elements are in
            // their own set.
            parent[i] = i;
        }
    }
 
    // Returns representative of x's set
    int find(int x)
    {
        // Finds the representative of the set
        // that x is an element of
        if (parent[x] != x) {
            // if x is not the parent of itself
            // Then x is not the representative of
            // his set,
            parent[x] = find(parent[x]);
 
            // so we recursively call Find on its parent
            // and move i's node directly under the
            // representative of this set
        }
 
        return parent[x];
    }
 
    // Unites the set that includes x and the set
    // that includes x
    void union(int x, int y)
    {
        // Find representatives of two sets
        int xRoot = find(x), yRoot = find(y);
 
        // Elements are in the same set, no need
        // to unite anything.
        if (xRoot == yRoot)
            return;
 
        // If x's rank is less than y's rank
        if (rank[xRoot] < rank[yRoot])
 
            // Then move x under y  so that depth
            // of tree remains less
            parent[xRoot] = yRoot;
 
        // Else if y's rank is less than x's rank
        else if (rank[yRoot] < rank[xRoot])
 
            // Then move y under x so that depth of
            // tree remains less
            parent[yRoot] = xRoot;
 
        else // if ranks are the same
        {
            // Then move y under x (doesn't matter
            // which one goes where)
            parent[yRoot] = xRoot;
 
            // And increment the result tree's
            // rank by 1
            rank[xRoot] = rank[xRoot] + 1;
        }
    }
}
 
// Driver code
public class Main {
    public static void main(String[] args)
    {
        // Let there be 5 persons with ids as
        // 0, 1, 2, 3 and 4
        int n = 5;
        DisjointUnionSets dus =
                new DisjointUnionSets(n);
 
        // 0 is a friend of 2
        dus.union(0, 2);
 
        // 4 is a friend of 2
        dus.union(4, 2);
 
        // 3 is a friend of 1
        dus.union(3, 1);
 
        // Check if 4 is a friend of 0
        if (dus.find(4) == dus.find(0))
            System.out.println("Yes");
        else
            System.out.println("No");
 
        // Check if 1 is a friend of 0
        if (dus.find(1) == dus.find(0))
            System.out.println("Yes");
        else
            System.out.println("No");
    }
}


Python3




# Python3 program to implement Disjoint Set Data
# Structure.
 
class DisjSet:
    def __init__(self, n):
        # Constructor to create and
        # initialize sets of n items
        self.rank = [1] * n
        self.parent = [i for i in range(n)]
 
 
    # Finds set of given item x
    def find(self, x):
         
        # Finds the representative of the set
        # that x is an element of
        if (self.parent[x] != x):
             
            # if x is not the parent of itself
            # Then x is not the representative of
            # its set,
            self.parent[x] = self.find(self.parent[x])
             
            # so we recursively call Find on its parent
            # and move i's node directly under the
            # representative of this set
 
        return self.parent[x]
 
 
    # Do union of two sets represented
    # by x and y.
    def Union(self, x, y):
         
        # Find current sets of x and y
        xset = self.find(x)
        yset = self.find(y)
 
        # If they are already in same set
        if xset == yset:
            return
 
        # Put smaller ranked item under
        # bigger ranked item if ranks are
        # different
        if self.rank[xset] < self.rank[yset]:
            self.parent[xset] = yset
 
        else if self.rank[xset] > self.rank[yset]:
            self.parent[yset] = xset
 
        # If ranks are same, then move y under
        # x (doesn't matter which one goes where)
        # and increment rank of x's tree
        else:
            self.parent[yset] = xset
            self.rank[xset] = self.rank[xset] + 1
 
# Driver code
obj = DisjSet(5)
obj.Union(0, 2)
obj.Union(4, 2)
obj.Union(3, 1)
if obj.find(4) == obj.find(0):
    print('Yes')
else:
    print('No')
if obj.find(1) == obj.find(0):
    print('Yes')
else:
    print('No')
 
# This code is contributed by ng24_7.


C#




// A C# program to implement 
// Disjoint Set Data Structure.
using System;
     
class DisjointUnionSets
{
    int[] rank, parent;
    int n;
 
    // Constructor
    public DisjointUnionSets(int n)
    {
        rank = new int[n];
        parent = new int[n];
        this.n = n;
        makeSet();
    }
 
    // Creates n sets with single item in each
    public void makeSet()
    {
        for (int i = 0; i < n; i++)
        {
            // Initially, all elements are in
            // their own set.
            parent[i] = i;
        }
    }
 
    // Returns representative of x's set
    public int find(int x)
    {
        // Finds the representative of the set
        // that x is an element of
        if (parent[x] != x)
        {
             
            // if x is not the parent of itself
            // Then x is not the representative of
            // his set,
            parent[x] = find(parent[x]);
 
            // so we recursively call Find on its parent
            // and move i's node directly under the
            // representative of this set
        }
        return parent[x];
    }
 
    // Unites the set that includes x and
    // the set that includes x
    public void union(int x, int y)
    {
        // Find representatives of two sets
        int xRoot = find(x), yRoot = find(y);
 
        // Elements are in the same set,
        // no need to unite anything.
        if (xRoot == yRoot)
            return;
 
        // If x's rank is less than y's rank
        if (rank[xRoot] < rank[yRoot])
 
            // Then move x under y so that depth
            // of tree remains less
            parent[xRoot] = yRoot;
 
        // Else if y's rank is less than x's rank
        else if (rank[yRoot] < rank[xRoot])
 
            // Then move y under x so that depth of
            // tree remains less
            parent[yRoot] = xRoot;
 
        else // if ranks are the same
        {
            // Then move y under x (doesn't matter
            // which one goes where)
            parent[yRoot] = xRoot;
 
            // And increment the result tree's
            // rank by 1
            rank[xRoot] = rank[xRoot] + 1;
        }
    }
}
 
// Driver code
class GFG
{
    public static void Main(String[] args)
    {
        // Let there be 5 persons with ids as
        // 0, 1, 2, 3 and 4
        int n = 5;
        DisjointUnionSets dus =
                new DisjointUnionSets(n);
 
        // 0 is a friend of 2
        dus.union(0, 2);
 
        // 4 is a friend of 2
        dus.union(4, 2);
 
        // 3 is a friend of 1
        dus.union(3, 1);
 
        // Check if 4 is a friend of 0
        if (dus.find(4) == dus.find(0))
            Console.WriteLine("Yes");
        else
            Console.WriteLine("No");
 
        // Check if 1 is a friend of 0
        if (dus.find(1) == dus.find(0))
            Console.WriteLine("Yes");
        else
            Console.WriteLine("No");
    }
}
 
// This code is contributed by Rajput-Ji


Javascript




class DisjSet {
    constructor(n) {
        this.rank = new Array(n);
        this.parent = new Array(n);
        this.n = n;
        this.makeSet();
    }
 
    makeSet() {
        for (let i = 0; i < this.n; i++) {
            this.parent[i] = i;
        }
    }
 
    find(x) {
        if (this.parent[x] !== x) {
            this.parent[x] = this.find(this.parent[x]);
        }
        return this.parent[x];
    }
 
    Union(x, y) {
        let xset = this.find(x);
        let yset = this.find(y);
 
        if (xset === yset) return;
 
        if (this.rank[xset] < this.rank[yset]) {
            this.parent[xset] = yset;
        } else if (this.rank[xset] > this.rank[yset]) {
            this.parent[yset] = xset;
        } else {
            this.parent[yset] = xset;
            this.rank[xset] = this.rank[xset] + 1;
        }
    }
}
 
// usage example
let obj = new DisjSet(5);
obj.Union(0, 2);
obj.Union(4, 2);
obj.Union(3, 1);
 
if (obj.find(4) === obj.find(0)) {
  console.log("Yes");
} else {
  console.log("No");
}
if (obj.find(1) === obj.find(0)) {
  console.log("Yes");
} else {
  console.log("No");
}


Output

Yes
No

The time complexity of creating n single item sets is O(n). The time complexity of find() and Union() operations is O(log n). Hence, the overall time complexity of the Disjoint Set Data Structure is O(n + log n).

The space complexity is O(n) because we need to store n elements in the Disjoint Set Data Structure.

Applications of Disjoint set Union: 

S. No.

Problem

Practice link

1

Kruskal’s Minimum Spanning Tree Algorithm.

solve

2

Job Sequencing Problem.

solve

3

Cycle Detection

solve

4

Number of pairs

solve

5

City With the Smallest Number of Neighbors at a Threshold Distance

solve

Related Articles: 
Union-Find Algorithm | Set 1 (Detect Cycle in an Undirected Graph) 
Union-Find Algorithm | Set 2 (Union By Rank and Path Compression)
 

Try to solve this problem and check how much you learnt and do comment on the complexity of the given question.
This article is contributed by Nikhil Tekwani. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. 

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above 


My Personal Notes arrow_drop_up
Last Updated : 13 Apr, 2023
Like Article
Save Article
Similar Reads
Related Tutorials