Skip to content

Commit

Permalink
added Union Find progression basic, path_compression, quickfind, quic…
Browse files Browse the repository at this point in the history
…kunion, optimized
  • Loading branch information
TheDoctor561 committed Oct 2, 2022
1 parent 586da8c commit 4520d84
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 0 deletions.
45 changes: 45 additions & 0 deletions Graphs/UnionFind/DisjointSet/01_basic_disjointset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# The vey basics of union find and disjoint sets
# Basically an array and within that array lies a disjoint set


# There are two functions when discussing disjoint sets

# find(a) which takes in a single argument and returns the root of
# that particular node

# union(a,b) which takes in two arguments and combines them together
# let's watch a quick video on how this works and then implement from there

# First lets implement UnionFind as an object and instantiate it with an array

class UnionFind:
def __init__(self, size):
self.root = [i for i in range(size)]

# union connects two nodes with a left bias meaning that b will always
# connect to a
def union(self, x, y):
rootX = self.find(x)
rootY = self.find(y)
if rootX != rootY:
for i in range(len(self.root)):
if self.root[i] == rootY:
self.root[i] = rootX

# takes in a node a and returns the root node of such
def find(self, a):
while a != self.root[a]:
a = self.root[a]
return a

uu = UnionFind(10)

print(uu.root)
uu.union(0,1)
uu.union(0,2)
uu.union(1,3)
uu.union(4,8)
uu.union(5,6)
uu.union(5,7)
print(uu.root)
print([i for i in range(10)])
35 changes: 35 additions & 0 deletions Graphs/UnionFind/DisjointSet/02_path_compression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

class UnionFind:
def __init__(self,size):
self.root = [i for i in range(size)]

def find(self, n):
if self.root[n] == n:
return n

self.root[n] = self.find(self.root[n])
return self.root[n]
# quick union
def union(self, a, b):
fa = self.find(a)
fb = self.find(b)
if fa != fb:
self.root[fa] = fb

def connected(self, x, y):
return self.find(x) == self.find(y)
# Test Case
uf = UnionFind(10)
# 1-2-5-6-7 3-8-9 4
uf.union(1, 2)
uf.union(2, 5)
uf.union(5, 6)
uf.union(6, 7)
uf.union(3, 8)
uf.union(8, 9)
print(uf.connected(1, 5)) # true
print(uf.connected(5, 7)) # true
print(uf.connected(4, 9)) # false
# 1-2-5-6-7 3-8-9-4
uf.union(9, 4)
print(uf.connected(4, 9)) # true
37 changes: 37 additions & 0 deletions Graphs/UnionFind/DisjointSet/03_quickfind_disjoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class UnionFind:
def __init__(self, size):
self.root = [i for i in range(size)]
# changing quickfind to have the parent node be stored in the array
# effectively making it an O(1) operation to find the root of a given node
# however, union will take a hit in performance

def find(self, n):
return self.root[n]

def union(self, a, b):
fa = self.find(a)
fb = self.find(b)
if fa != fb:
for i, v in enumerate(self.root):
if fa == v:
self.root[i] = fb

def connected(self, x, y):
return self.find(x) == self.find(y)


# Test Case
uf = UnionFind(10)
# 1-2-5-6-7 3-8-9 4
uf.union(1, 2)
uf.union(2, 5)
uf.union(5, 6)
uf.union(6, 7)
uf.union(3, 8)
uf.union(8, 9)
print(uf.connected(1, 5)) # true
print(uf.connected(5, 7)) # true
print(uf.connected(4, 9)) # false
# 1-2-5-6-7 3-8-9-4
uf.union(9, 4)
print(uf.connected(4, 9)) # true
44 changes: 44 additions & 0 deletions Graphs/UnionFind/DisjointSet/04_quickunion_disjoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# The vey basics of union find and disjoint sets
# Basically an array and within that array lies a disjoint set


# There are two functions when discussing disjoint sets

# find(a) which takes in a single argument and returns the root of
# that particular node

# union(a,b) which takes in two arguments and combines them together
# let's watch a quick video on how this works and then implement from there

# First lets implement UnionFind as an object and instantiate it with an array

class UnionFind:
def __init__(self, size):
self.root = [i for i in range(size)]

# union connects two nodes with a left bias meaning that b will always
# connect to a
def union(self,a,b):
# Basically we want to take the parent node of the given thing
fa = self.find(a)
fb = self.find(b)
if fa != fb:
self.root[fa] = fb

# takes in a node a and returns the root node of such
def find(self, a):
while a != self.root[a]:
a = self.root[a]
return a

uu = UnionFind(10)

print(uu.root)
uu.union(0,1)
uu.union(0,2)
uu.union(1,3)
uu.union(4,8)
uu.union(5,6)
uu.union(5,7)
print(uu.root)
print([i for i in range(10)])
44 changes: 44 additions & 0 deletions Graphs/UnionFind/DisjointSet/05_optimized_disjoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Optimized union find program that implements union by rank

class UnionFind:
def __init__(self, size):
self.root = [i for i in range(size)]
self.rank = [1] * size

# Recurrsively update root
def find(self, n):
if self.root[n] != n:
self.root[n] = self.find(self.root[n])
return self.root[n]

def union(self, a, b):
fa = self.find(a)
fb = self.find(b)

if fa != fb:
if self.rank[fa] > self.rank[fb]:
self.root[fb] = fa
elif self.rank[fa] < self.rank[fb]:
self.root[fa] = fb
else:
self.root[fa] = fb
self.rank[fb] += 1

def connected(self, x, y):
return self.find(x) == self.find(y)

# Test Case
uf = UnionFind(10)
# 1-2-5-6-7 3-8-9 4
uf.union(1, 2)
uf.union(2, 5)
uf.union(5, 6)
uf.union(6, 7)
uf.union(3, 8)
uf.union(8, 9)
print(uf.connected(1, 5)) # true
print(uf.connected(5, 7)) # true
print(uf.connected(4, 9)) # false
# 1-2-5-6-7 3-8-9-4
uf.union(9, 4)
print(uf.connected(4, 9)) # true
Empty file.

0 comments on commit 4520d84

Please sign in to comment.