33// is used to efficiently maintain connected components in a graph that undergoes dynamic changes,
44// such as edges being added or removed over time
55// Worst Case Time Complexity: The time complexity of find operation is nearly constant or
6- //O(α(n)), where where α(n) is the inverse Ackermann function
6+ //O(α(n)), where α(n) is the inverse Ackermann function
77// practically, this is a very slowly growing function making the time complexity for find
88//operation nearly constant.
99// The time complexity of the union operation is also nearly constant or O(α(n))
1010// Worst Case Space Complexity: O(n), where n is the number of nodes or element in the structure
1111// Reference: https://www.scaler.com/topics/data-structures/disjoint-set/
12+ // https://en.wikipedia.org/wiki/Disjoint-set_data_structure
1213// Author: Mugdha Behere[https://github.com/MugdhaBehere]
1314// see: unionfind.go, unionfind_test.go
1415
@@ -17,43 +18,45 @@ package graph
1718// Defining the union-find data structure
1819type UnionFind struct {
1920 parent []int
20- size []int
21+ rank []int
2122}
2223
2324// Initialise a new union find data structure with s nodes
2425func NewUnionFind (s int ) UnionFind {
2526 parent := make ([]int , s )
26- size := make ([]int , s )
27- for k := 0 ; k < s ; k ++ {
28- parent [k ] = k
29- size [ k ] = 1
27+ rank := make ([]int , s )
28+ for i := 0 ; i < s ; i ++ {
29+ parent [i ] = i
30+ rank [ i ] = 1
3031 }
31- return UnionFind {parent , size }
32+ return UnionFind {parent , rank }
3233}
3334
34- // to find the root of the set to which the given element belongs, the Find function serves the purpose
35- func (u UnionFind ) Find (q int ) int {
36- for q != u .parent [q ] {
37- q = u .parent [q ]
35+ // Find finds the root of the set to which the given element belongs.
36+ // It performs path compression to make future Find operations faster.
37+ func (u * UnionFind ) Find (q int ) int {
38+ if q != u .parent [q ] {
39+ u .parent [q ] = u .Find (u .parent [q ])
3840 }
39- return q
41+ return u . parent [ q ]
4042}
4143
42- // to merge two sets to which the given elements belong, the Union function serves the purpose
43- func (u UnionFind ) Union (a , b int ) UnionFind {
44- rootP := u .Find (a )
45- rootQ := u .Find (b )
44+ // Union merges the sets, if not already merged, to which the given elements belong.
45+ // It performs union by rank to keep the tree as flat as possible.
46+ func (u * UnionFind ) Union (p , q int ) {
47+ rootP := u .Find (p )
48+ rootQ := u .Find (q )
4649
4750 if rootP == rootQ {
48- return u
51+ return
4952 }
5053
51- if u .size [rootP ] < u .size [rootQ ] {
54+ if u .rank [rootP ] < u .rank [rootQ ] {
5255 u .parent [rootP ] = rootQ
53- u .size [rootQ ] += u .size [rootP ]
56+ } else if u .rank [rootP ] > u .rank [rootQ ] {
57+ u .parent [rootQ ] = rootP
5458 } else {
5559 u .parent [rootQ ] = rootP
56- u .size [rootP ] += u . size [ rootQ ]
60+ u .rank [rootP ]++
5761 }
58- return u
5962}
0 commit comments