Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a328b66

Browse files
authored
Merge pull request #399 from eshaanrawat1/main
Added Union Find Data Structure
2 parents 7d8a459 + 4f7e345 commit a328b66

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Union Find (Disjoint Set Union) - Implementation and Use
2+
3+
## Table of Contents
4+
- [Why Union Find?](#why-union-find)
5+
- [Functions and Examples](#functions-and-examples)
6+
- [Setup](#setup)
7+
- [Additional Resources](#additional-resources)
8+
- [Leetcode Questions](#leetcode-questions)
9+
10+
## Why Union Find?
11+
Union Find is a popular data structure that allows us to solve many different types of graph
12+
problems. It works best with undirected graphs, and it allows us to figure out whether a node
13+
is connected to another node.
14+
15+
Some problems it can be used to solve:
16+
- Find the minimum spanning tree in a graph (Kruskal's)
17+
- Check if there is a path between two nodes
18+
- Finding redundant edges
19+
- Representing networks
20+
21+
22+
## Functions and Examples
23+
Union Find seems complex at first, but it is actually a lot easier when you understand that there are
24+
only two functions.
25+
- Find(n) : returns the parent of a node n
26+
- Union(n1, n2) : connects n1 and n2 if they are not previously connected
27+
28+
Let's look at an example!
29+
```python
30+
u = UnionFind(7) # create a UnionFind object with 7 nodes (numbered 0 to 6)
31+
32+
u.union(0, 1) # connects 0 and 1 together
33+
u.union(5, 6) # connects 5 and 6 together
34+
35+
u.find(1) # returns 0, since 0 is parent of 1
36+
u.find(5) # returns 5, since 5 is its own parent
37+
38+
u.union(1, 2) # connects 2 to the component 0-1
39+
u.find(2) # 2s parent is now 0
40+
41+
# Now our structure looks like this
42+
43+
# 0-1-2 3 4 5-6
44+
45+
u.union(1, 6) # first we find the parents of 1 and 6
46+
# parents are 0, and 5
47+
# connect the smaller component to the bigger
48+
# now 5's parent is 0
49+
50+
u.find(6) # now this goes:
51+
# 6 parent is 5 -> 5 parent is 0 -> 0 is its own parent
52+
```
53+
54+
And that's it! You can use the sample code to test different examples with Union Find.
55+
In the code, par keeps track of the parent of each node and rank keeps track of the size of
56+
each component.
57+
58+
## Setup
59+
60+
First clone the repo
61+
> `cd union_find` to get into this folder.
62+
> call the verify function anywhere, consider adding ``` if __name__ == '__main__'```
63+
> `python union_find.py` to run the demo
64+
65+
You can modify the structure in the verify function and play around with it.
66+
67+
## Additional Resources
68+
69+
Here are some resources I found useful when learning:
70+
- Neetcode Graph Videos on YouTube
71+
- William Fiset - Union Find Video on YouTube
72+
- Union Find Medium Article by Claire Lee
73+
- Union Find Visualizer - Visualgo
74+
75+
## Leetcode Questions
76+
- 200 - Number of Islands
77+
- 684 - Redundant Connection
78+
- 695 - Max Area of an Island
79+
- 827 - Making a Large Island
80+
- 2316 - Count Unreachable Pairs of Nodes in an Undirected Graph
81+
- 2421 - Maximum Score of a Good Path
82+
- 2709 - Greatest Common Divisor Traversal
83+
84+
I hope this was helpful. If there are any mistakes or issues or if you want to contribute to union find, feel free to contact me at rawateshaan0 [at] gmail [dot] com
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Basic implementation of the Union Find data structure
2+
# Assume we have n nodes labeled from 0 to n - 1
3+
4+
class UnionFind:
5+
def __init__(self, n):
6+
# every node is originally its own parent
7+
self.par = [i for i in range(n)]
8+
# self.par = list(range(n)) -- also valid
9+
10+
# every node originally is in its own
11+
# component of size 1 - this changes during
12+
# the union operation
13+
self.rank = [1] * n
14+
15+
def find(self, n) -> int:
16+
'''
17+
Finds the parent node of n
18+
'''
19+
20+
# can be optimized with path compression
21+
while n != self.par[n]:
22+
n = self.par[n]
23+
return n
24+
25+
26+
def union(self, n1, n2) -> bool:
27+
'''
28+
Connects two nodes together if not
29+
already connected
30+
'''
31+
32+
# find the parent of node 1 and 2
33+
p1 = self.find(n1)
34+
p2 = self.find(n2)
35+
36+
# nodes are already connected
37+
# cannot union together
38+
if p1 == p2:
39+
return False
40+
41+
# for efficiency, make bigger component
42+
# parent of smaller component - reduces
43+
# number of steps we have to take in find()
44+
45+
if self.rank[p1] >= self.rank[p2]:
46+
# p2 is smaller, so when union it has a
47+
# new parent, p1
48+
self.par[p2] = p1
49+
50+
# p1 gets all the nodes of p2, increasing
51+
# its rank, or size
52+
self.rank[p1] += self.rank[p2]
53+
else:
54+
self.par[p1] = p2
55+
self.rank[p2] += self.rank[p1]
56+
57+
return True
58+
59+
def nodes_connected(self, n1, n2) -> bool:
60+
'''
61+
Returns if two nodes are connected
62+
'''
63+
64+
# connected if parent is the same
65+
return self.find(n1) == self.find(n2)
66+
67+
68+
69+
def verify():
70+
n = 7
71+
u = UnionFind(n)
72+
73+
# False, nodes not connected
74+
print(u.nodes_connected(0, 1))
75+
76+
# True, just connected 0 and 1
77+
u.union(0, 1)
78+
print(u.nodes_connected(0, 1))
79+
80+
# Rank is 2, includes 0 and 1
81+
print(u.rank[0])
82+
83+
u.union(4, 5)
84+
u.union(1, 4)
85+
86+
# True, 0 - 1 and 4 - 5 are connected
87+
# 1 to 4 connects both components
88+
print(u.nodes_connected(0, 5))

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /