1
1
// KRUSKAL'S ALGORITHM
2
- // https://cp-algorithms.com/data_structures/disjoint_set_union.html
3
- // https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html
2
+ // Reference: Kruskal's Algorithm: https://www.scaler.com/topics/data-structures/kruskal-algorithm/
3
+ // Reference: Union Find Algorithm: https://www.scaler.com/topics/data-structures/disjoint-set/
4
+ // Author: Author: Mugdha Behere[https://github.com/MugdhaBehere]
5
+ // Worst Case Time Complexity: O(E log E), where E is the number of edges.
6
+ // Worst Case Space Complexity: O(V + E), where V is the number of vertices and E is the number of edges.
7
+ // see kruskal.go, kruskal_test.go
4
8
5
9
package graph
6
10
@@ -10,104 +14,44 @@ import (
10
14
11
15
type Vertex int
12
16
13
- // Edge describes the edge of a weighted graph
14
17
type Edge struct {
15
18
Start Vertex
16
19
End Vertex
17
20
Weight int
18
21
}
19
22
20
- // DisjointSetUnionElement describes what an element of DSU looks like
21
- type DisjointSetUnionElement struct {
22
- Parent Vertex
23
- Rank int
24
- }
25
-
26
- // DisjointSetUnion is a data structure that treats its elements as separate sets
27
- // and provides fast operations for set creation, merging sets, and finding the parent
28
- // of the given element of a set.
29
- type DisjointSetUnion []DisjointSetUnionElement
30
-
31
- // NewDSU will return an initialised DSU using the value of n
32
- // which will be treated as the number of elements out of which
33
- // the DSU is being made
34
- func NewDSU (n int ) * DisjointSetUnion {
35
-
36
- dsu := DisjointSetUnion (make ([]DisjointSetUnionElement , n ))
37
- return & dsu
38
- }
39
-
40
- // MakeSet will create a set in the DSU for the given node
41
- func (dsu DisjointSetUnion ) MakeSet (node Vertex ) {
42
-
43
- dsu [node ].Parent = node
44
- dsu [node ].Rank = 0
45
- }
46
-
47
- // FindSetRepresentative will return the parent element of the set the given node
48
- // belongs to. Since every single element in the path from node to parent
49
- // has the same parent, we store the parent value for each element in the
50
- // path. This reduces consequent function calls and helps in going from O(n)
51
- // to O(log n). This is known as path compression technique.
52
- func (dsu DisjointSetUnion ) FindSetRepresentative (node Vertex ) Vertex {
53
-
54
- if node == dsu [node ].Parent {
55
- return node
56
- }
57
-
58
- dsu [node ].Parent = dsu .FindSetRepresentative (dsu [node ].Parent )
59
- return dsu [node ].Parent
60
- }
61
-
62
- // unionSets will merge two given sets. The naive implementation of this
63
- // always combines the secondNode's tree with the firstNode's tree. This can lead
64
- // to creation of trees of length O(n) so we optimize by attaching the node with
65
- // smaller rank to the node with bigger rank. Rank represents the upper bound depth of the tree.
66
- func (dsu DisjointSetUnion ) UnionSets (firstNode Vertex , secondNode Vertex ) {
67
-
68
- firstNode = dsu .FindSetRepresentative (firstNode )
69
- secondNode = dsu .FindSetRepresentative (secondNode )
70
-
71
- if firstNode != secondNode {
72
-
73
- if dsu [firstNode ].Rank < dsu [secondNode ].Rank {
74
- firstNode , secondNode = secondNode , firstNode
75
- }
76
- dsu [secondNode ].Parent = firstNode
77
-
78
- if dsu [firstNode ].Rank == dsu [secondNode ].Rank {
79
- dsu [firstNode ].Rank ++
80
- }
81
- }
82
- }
83
-
84
- // KruskalMST will return a minimum spanning tree along with its total cost
85
- // to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is
86
- // the number of edges in the graph and n is number of nodes in it.
87
23
func KruskalMST (n int , edges []Edge ) ([]Edge , int ) {
24
+ // Initialize variables to store the minimum spanning tree and its total cost
25
+ var mst []Edge
26
+ var cost int
88
27
89
- var mst []Edge // The resultant minimum spanning tree
90
- var cost int = 0
91
-
92
- dsu := NewDSU (n )
28
+ // Create a new UnionFind data structure with 'n' nodes
29
+ u := NewUnionFind (n )
93
30
31
+ // Initialize each node in the UnionFind data structure
94
32
for i := 0 ; i < n ; i ++ {
95
- dsu .MakeSet (Vertex (i ))
33
+ u .parent [i ] = i
34
+ u .size [i ] = 1
96
35
}
97
36
37
+ // Sort the edges in non-decreasing order based on their weights
98
38
sort .SliceStable (edges , func (i , j int ) bool {
99
39
return edges [i ].Weight < edges [j ].Weight
100
40
})
101
41
42
+ // Iterate through the sorted edges
102
43
for _ , edge := range edges {
103
-
104
- if dsu . FindSetRepresentative ( edge .Start ) != dsu . FindSetRepresentative ( edge .End ) {
105
-
44
+ // Check if adding the current edge forms a cycle or not
45
+ if u . Find ( int ( edge .Start )) != u . Find ( int ( edge .End ) ) {
46
+ // Add the edge to the minimum spanning tree
106
47
mst = append (mst , edge )
48
+ // Add the weight of the edge to the total cost
107
49
cost += edge .Weight
108
- dsu .UnionSets (edge .Start , edge .End )
50
+ // Merge the sets containing the start and end vertices of the current edge
51
+ u = u .Union (int (edge .Start ), int (edge .End ))
109
52
}
110
53
}
111
54
55
+ // Return the minimum spanning tree and its total cost
112
56
return mst , cost
113
57
}
0 commit comments