Union Find Disjoint Set Data Structure in DSA C - Time & Space Complexity
We want to understand how fast the Union Find data structure works when connecting and checking groups.
How does the time needed change as we add more items?
Analyze the time complexity of the following code snippet.
// Find with path compression
int find(int parent[], int x) {
if (parent[x] != x) {
parent[x] = find(parent, parent[x]);
}
return parent[x];
}
// Union by rank
void unionSets(int parent[], int rank[], int a, int b) {
a = find(parent, a);
b = find(parent, b);
if (a != b) {
if (rank[a] < rank[b])
parent[a] = b;
else if (rank[b] < rank[a])
parent[b] = a;
else {
parent[b] = a;
rank[a]++;
}
}
}
This code finds the group leader of an element and merges two groups efficiently.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The recursive
findfunction that follows parent links to find the root. - How many times: Each
findcall may traverse up the tree, but path compression flattens it over time.
Initially, finding a root may take longer if trees are tall, but path compression and union by rank keep trees shallow.
| Input Size (n) | Approx. Operations per find/union |
|---|---|
| 10 | About 4-5 steps or less |
| 100 | About 5-6 steps or less |
| 1000 | About 6-7 steps or less |
Pattern observation: The steps grow very slowly, almost constant, even as input grows large.
Time Complexity: O(α(n))
This means each operation takes almost constant time, where α(n) is a very slow growing function.
[X] Wrong: "Each find or union takes linear time because it may traverse many parents."
[OK] Correct: Path compression and union by rank keep trees very flat, so operations are almost constant time, not linear.
Understanding this complexity shows you can handle efficient grouping problems, a common skill in many coding challenges.
"What if we removed path compression? How would the time complexity change?"
Practice
Union Find Disjoint Set data structure?Solution
Step 1: Understand the role of Union Find
The Union Find data structure is designed to keep track of which elements belong to which groups or sets, especially when these groups merge.Step 2: Compare with other data structures
Sorting, key-value storage, and priority queues serve different purposes unrelated to grouping connected components.Final Answer:
To efficiently track and merge groups of connected elements -> Option BQuick Check:
Union Find = track and merge groups [OK]
- Confusing Union Find with sorting algorithms
- Thinking it stores key-value pairs
- Assuming it manages priority queues
n elements in C?Solution
Step 1: Understand initialization of Union Find
Each element starts as its own parent, so parent[i] = i for all i from 0 to n-1.Step 2: Check each option
int parent[n]; for(int i=0; iFinal Answer:
int parent[n]; for(int i=0; i -> Option AQuick Check:
Initialize parent[i] = i [OK]
- Setting all parents to zero
- Using -1 as parent without meaning
- Assigning parent to n (out of range)
int parent[5];
for(int i=0; i<5; i++) parent[i] = i;
// Union operations
union_set(parent, 0, 1);
union_set(parent, 1, 2);
union_set(parent, 3, 4);
// Find operations
int a = find_set(parent, 2);
int b = find_set(parent, 4);
printf("%d %d", a, b);Assuming
union_set merges sets and find_set returns the root parent, what is the printed output?Solution
Step 1: Trace union operations
Initially, parent[i] = i for i=0..4.
union_set(0,1) merges sets containing 0 and 1, root becomes 0.
union_set(1,2) merges sets containing 1 and 2, root is 0 (since 1's root is 0).
union_set(3,4) merges sets containing 3 and 4, root becomes 3.Step 2: Trace find operations
find_set(2) returns root of 2, which is 0.
find_set(4) returns root of 4, which is 3.Final Answer:
0 3 -> Option AQuick Check:
Roots after unions: 2->0, 4->3 [OK]
- Assuming find_set returns the element itself
- Not updating roots after unions
- Mixing up which element is root
union_set but has a bug:void union_set(int parent[], int a, int b) {
int rootA = find_set(parent, a);
int rootB = find_set(parent, b);
if (rootA != rootB) {
parent[a] = rootB;
}
}What is the bug in this code?
Solution
Step 1: Analyze union assignment
The union should link the root of one set to the root of the other.
Assigning parent[a] = rootB is wrong because 'a' may not be a root.Step 2: Correct union assignment
It should assign parent[rootA] = rootB to merge sets properly.
This maintains the tree structure of the disjoint sets.Final Answer:
It assigns parent[a] instead of parent[rootA], breaking the set structure -> Option CQuick Check:
Union must link roots, not elements [OK]
- Assigning parent of non-root element
- Skipping root equality check
- Confusing parameters in find_set
union_set(parent, 0, 1); union_set(parent, 1, 2); union_set(parent, 3, 4); union_set(parent, 5, 6); union_set(parent, 2, 5);
How many distinct sets remain?
Solution
Step 1: Track unions step-by-step
Initially: 7 sets: {0}, {1}, {2}, {3}, {4}, {5}, {6}
union(0,1): {0,1}, {2}, {3}, {4}, {5}, {6}
union(1,2): {0,1,2}, {3}, {4}, {5}, {6}
union(3,4): {0,1,2}, {3,4}, {5}, {6}
union(5,6): {0,1,2}, {3,4}, {5,6}
union(2,5): merges sets {0,1,2} and {5,6} into {0,1,2,5,6}, {3,4}Step 2: Count remaining sets
Remaining sets are {0,1,2,5,6} and {3,4}.
Total distinct sets = 2.Final Answer:
2 -> Option DQuick Check:
Count sets after unions = 2 [OK]
- Forgetting last union merges two sets
- Counting elements instead of sets
- Assuming all unions merge all sets
Ready to prove it?
Pass the test and this pattern moves unknown
