Info
Why disjoint set is used ?? Let’s imagine a graph with two components.
DSU1
⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠
Text Elements
1
2
3
5
6
7
4
Link to original
- To find if
1
and5
belong to the same component we’ll doDFS
(O(N+E)) which is a brute force method.- Disjoint joint tells this in CONSTANT TIME.
- It’s used in dynamic graphs, graphs whose configurations keep on changing.
- It gives us functionalities like:
- findParent()
- Union - It basically connects two nodes during graph formation. There’re two methods for this:
- By Rank
- By Size
1.
- Imagine we did union till (6,7) and before we proceeds someone asks
4
&1
belong to the same component or not- The answer will be NO.
2.
- Now after all the operations are done,
4
&1
belong a single set.
Notes (Click to expand):
![[DSU-Notes.pdf |height=200]]
UNION BY RANK (LESS INTUITIVE):
public class Main {
static class DisjointSet {
private int[] parent;
private int[] rank;
public DisjointSet(int n) {
// Resized parent and rank to n+1 instead of n as it'll work for both 0-based indexing & 1 for 1-based indexing.
parent = new int[n + 1];
rank = new int[n + 1];
for (int i = 0; i <= n; i++) {
parent[i] = i;
rank[i] = 0;
}
}
public int findUltimateParent(int x) {
if (parent[x] != x) {
parent[x] = findUltimateParent(parent[x]); // Path compression
}
return parent[x];
}
public void unionByRank(int u, int v) {
int ulp_u = findUltimateParent(u);//ultimate parent of u
int ulp_v = findUltimateParent(v);//ultimate parent of v
if (ulp_u == ulp_v) return;
if (rank[ulp_u] < rank[ulp_v]) {
parent[ulp_u] = parent[ulp_v];
} else if (rank[ulp_u] > rank[ulp_v]) {
parent[ulp_v] = ulp_u;
} else {
/*
* In the else block, when the ranks of both ultimate parents are equal,
* we arbitrarily choose one ultimate parent (ulp_u) in this case) and
* make the other ultimate parent (ulp_v) its child.
* We also increment the rank of the chosen ultimate parent by 1.
*/
parent[ulp_v] = ulp_u; // Update parent directly with the ultimate parent
rank[ulp_u]++;
}
}
}
public static void main(String[] args) {
int numElements = 6;
DisjointSet dsu = new DisjointSet(numElements);
// Perform union operations
dsu.unionByRank(0, 1);
dsu.unionByRank(2, 3);
dsu.unionByRank(4, 5);
dsu.unionByRank(1, 3);
// Find the ultimate parent of elements
System.out.println("Ultimate parent of element 0: " + dsu.findUltimateParent(0));
System.out.println("Ultimate parent of element 2: " + dsu.findUltimateParent(2));
System.out.println("Ultimate parent of element 3: " + dsu.findUltimateParent(3));
// Check if elements belong to the same set
System.out.println("Elements 0 and 2 belong to the same set: " + (dsu.findUltimateParent(0) == dsu.findUltimateParent(2)));
System.out.println("Elements 1 and 5 belong to the same set: " + (dsu.findUltimateParent(1) == dsu.findUltimateParent(5)));
}
}
UNION BY SIZE (MORE INTUITIVE):
- Because in unionByRank we initially calculate the rank with the height but after path compression that height destroys and rank is no more intuitive.
- Here, smaller size set attaches to larger size set.
- By merging the smaller set into the larger set, we minimize the depth of the resulting tree and keep the tree more balanced.
public class Main {
static class DisjointSet {
private int[] parent;
private int[] size;
public DisjointSet(int n) {
// Resized parent and rank to n+1 instead of n as it'll work for both 0-based indexing & 1 for 1-based indexing.
parent = new int[n + 1];
size = new int[n + 1];
for (int i = 0; i <= n; i++) {
parent[i] = i;
size[i] = 1;
}
}
public int findUltimateParent(int x) {
if (parent[x] != x) {
parent[x] = findUltimateParent(parent[x]); // Path compression
}
return parent[x];
}
public void unionBySize(int u, int v) {
int ulp_u = findUltimateParent(u);
int ulp_v = findUltimateParent(v);
if (ulp_u == ulp_v) return;
if (size[ulp_u] < size[ulp_v]) {
parent[ulp_u] = ulp_v;
size[ulp_v] += size[ulp_u];
} else {
parent[ulp_v] = ulp_u;
size[ulp_u] += size[ulp_v];
}
}
}
public static void main(String[] args) {
int numElements = 6;
DisjointSet dsu = new DisjointSet(numElements);
// Perform union operations
dsu.unionBySize(0, 1);
dsu.unionBySize(2, 3);
dsu.unionBySize(4, 5);
dsu.unionBySize(1, 3);
// Find the ultimate parent of elements
System.out.println("Ultimate parent of element 0: " + dsu.findUltimateParent(0));
System.out.println("Ultimate parent of element 2: " + dsu.findUltimateParent(2));
System.out.println("Ultimate parent of element 3: " + dsu.findUltimateParent(3));
// Check if elements belong to the same set
System.out.println("Elements 0 and 2 belong to the same set: " + (dsu.findUltimateParent(0) == dsu.findUltimateParent(2)));
System.out.println("Elements 1 and 5 belong to the same set: " + (dsu.findUltimateParent(1) == dsu.findUltimateParent(5)));
}
}