3
3
// is used to efficiently maintain connected components in a graph that undergoes dynamic changes,
4
4
// such as edges being added or removed over time
5
5
// 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
7
7
// practically, this is a very slowly growing function making the time complexity for find
8
8
//operation nearly constant.
9
9
// The time complexity of the union operation is also nearly constant or O(α(n))
10
10
// Worst Case Space Complexity: O(n), where n is the number of nodes or element in the structure
11
11
// Reference: https://www.scaler.com/topics/data-structures/disjoint-set/
12
+ // https://en.wikipedia.org/wiki/Disjoint-set_data_structure
12
13
// Author: Mugdha Behere[https://github.com/MugdhaBehere]
13
14
// see: unionfind.go, unionfind_test.go
14
15
@@ -17,43 +18,45 @@ package graph
17
18
// Defining the union-find data structure
18
19
type UnionFind struct {
19
20
parent []int
20
- size []int
21
+ rank []int
21
22
}
22
23
23
24
// Initialise a new union find data structure with s nodes
24
25
func NewUnionFind (s int ) UnionFind {
25
26
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
30
31
}
31
- return UnionFind {parent , size }
32
+ return UnionFind {parent , rank }
32
33
}
33
34
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 ])
38
40
}
39
- return q
41
+ return u . parent [ q ]
40
42
}
41
43
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 )
46
49
47
50
if rootP == rootQ {
48
- return u
51
+ return
49
52
}
50
53
51
- if u .size [rootP ] < u .size [rootQ ] {
54
+ if u .rank [rootP ] < u .rank [rootQ ] {
52
55
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
54
58
} else {
55
59
u .parent [rootQ ] = rootP
56
- u .size [rootP ] += u . size [ rootQ ]
60
+ u .rank [rootP ]++
57
61
}
58
- return u
59
62
}
0 commit comments