-
Notifications
You must be signed in to change notification settings - Fork 293
/
DisJointSet.cs
123 lines (102 loc) · 3.06 KB
/
DisJointSet.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Advanced.Algorithms.DataStructures;
/// <summary>
/// A disjoint set implementation.
/// </summary>
public class DisJointSet<T> : IEnumerable<T>
{
/// <summary>
/// A Map for faster access for members.
/// </summary>
private readonly Dictionary<T, DisJointSetNode<T>> set = new();
public int Count { get; private set; }
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return set.Values.Select(x => x.Data).GetEnumerator();
}
/// <summary>
/// Creates a new set with given member.
/// Time complexity: log(n).
/// </summary>
public void MakeSet(T member)
{
if (set.ContainsKey(member)) throw new Exception("A set with given member already exists.");
var newSet = new DisJointSetNode<T>
{
Data = member,
Rank = 0
};
//Root's Parent is Root itself
newSet.Parent = newSet;
set.Add(member, newSet);
Count++;
}
/// <summary>
/// Returns the reference member of the set where this member is part of.
/// Time complexity: log(n).
/// </summary>
public T FindSet(T member)
{
if (!set.ContainsKey(member)) throw new Exception("No such set with given member.");
return FindSet(set[member]).Data;
}
/// <summary>
/// Recursively move up in the set tree till root
/// and return the Root.
/// Does path Compression on all visited members on way to root
/// by pointing their parent to Root.
/// </summary>
private DisJointSetNode<T> FindSet(DisJointSetNode<T> node)
{
var parent = node.Parent;
if (node != parent)
{
//compress path by setting parent to Root
node.Parent = FindSet(node.Parent);
return node.Parent;
}
//reached root so return the Root (reference Member)
return parent;
}
/// <summary>
/// Union's given member's sets if given members are in differant sets.
/// Otherwise does nothing.
/// Time complexity: log(n).
/// </summary>
public void Union(T memberA, T memberB)
{
var rootA = FindSet(memberA);
var rootB = FindSet(memberB);
if (rootA.Equals(rootB)) return;
var nodeA = set[rootA];
var nodeB = set[rootB];
//equal rank so just pick any of two as Root
//and increment rank
if (nodeA.Rank == nodeB.Rank)
{
nodeB.Parent = nodeA;
nodeA.Rank++;
}
else
{
//pick max Rank node as root
if (nodeA.Rank < nodeB.Rank)
nodeA.Parent = nodeB;
else
nodeB.Parent = nodeA;
}
}
}
internal class DisJointSetNode<T>
{
internal T Data { get; set; }
internal int Rank { get; set; }
internal DisJointSetNode<T> Parent { get; set; }
}