Skip to content

Commit 1fb4f95

Browse files
committed
Add find() and union() methods for union-find implementation
1 parent b634f32 commit 1fb4f95

1 file changed

Lines changed: 54 additions & 2 deletions

File tree

src/boruvkas_algorithm/boruvka.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ def __init__(self, num_vertices: int):
1818
Args:
1919
num_vertices: The number of vertices to generate in the graph.
2020
"""
21-
self.vertices = list(range(num_vertices))
21+
self.vertices: list[int] = list(range(num_vertices))
2222
# [(vertex_1, vertex_2, weight)]
23-
self.edges = []
23+
self.edges: list[tuple[int, int, int]] = []
24+
# Each node is its own parent initially.
25+
self.parent: list[int] = list(range(num_vertices))
26+
# Each tree has size 1 (itself) initially.
27+
self.rank: list[int] = [1] * num_vertices
2428

2529
def add_edge(self, vertex_1: int, vertex_2: int, weight: int) -> None:
2630
"""
@@ -47,6 +51,54 @@ def print_graph_info(self) -> None:
4751
for edge in sorted(self.edges):
4852
print(f" {edge}")
4953

54+
def find(self, node: int) -> int:
55+
"""
56+
Finds the root parent of the node using path compression.
57+
58+
Args:
59+
node: The node to find the root parent of.
60+
61+
Returns:
62+
The root parent of the node.
63+
"""
64+
cur_parent = self.parent[node]
65+
while cur_parent != self.parent[cur_parent]:
66+
# Compress the links as we go up the chain of parents to make
67+
# it faster to traverse in the future - amortised O(a(n)) time,
68+
# where a(n) is the inverse Ackermann function.
69+
self.parent[cur_parent] = self.parent[self.parent[cur_parent]]
70+
cur_parent = self.parent[cur_parent]
71+
72+
return cur_parent
73+
74+
def union(self, node1: int, node2: int) -> bool:
75+
"""
76+
Combines the two nodes into the larger segment.
77+
78+
Args:
79+
node1: The first node to combine.
80+
node2: The second node to combine.
81+
82+
Returns:
83+
True if the nodes were combined, False if they were already in the
84+
same segment.
85+
"""
86+
root1 = self.find(node1)
87+
root2 = self.find(node2)
88+
# If they have the same root parent, a cycle exists.
89+
if root1 == root2:
90+
return False
91+
92+
# Combine the two nodes into the larger segment based on the rank.
93+
if self.rank[root1] > self.rank[root2]:
94+
self.parent[root2] = root1
95+
self.rank[root1] += self.rank[root2]
96+
else:
97+
self.parent[root1] = root2
98+
self.rank[root2] += self.rank[root1]
99+
100+
return True
101+
50102
def merge_components(
51103
self,
52104
vertex_to_component: Dict[int, int],

0 commit comments

Comments
 (0)