-
Notifications
You must be signed in to change notification settings - Fork 312
/
DisjointSet.ts
93 lines (77 loc) · 2.41 KB
/
DisjointSet.ts
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
class DisjointSet {
private _parents: Array<number>;
private _ranks: Array<number>;
private _setSizes: Array<number>;
private _size: number;
constructor(size: number) {
this._parents = Array(size)
.fill(null)
.map((_, index) => index);
this._ranks = Array(size).fill(0);
this._setSizes = Array(size).fill(1);
this._size = size;
}
/**
* The total number of elements in the elements set.
* @return The total number of elements in the elements set.
*/
sizeOf(element: number): number {
return this._setSizes[this.find(element)];
}
/**
* The number of disjoint sets.
* @return {number} The number of disjoint sets.
*/
get size(): number {
return this._size;
}
/**
* Find the set that an element belongs to.
* @param {number} element The element we are interested in.
* @return {number} The root of the set that the element belongs to.
*/
find(element: number): number {
if (this._parents[element] !== element) {
// Path compression heuristic.
this._parents[element] = this.find(this._parents[element]);
}
return this._parents[element];
}
/**
* Determines if two elements are from the same set.
* @param {number} elementA The first element.
* @param {number} elementB The second element.
* @return {boolean} Whether the two elements belong to the same set.
*/
isSameSet(elementA: number, elementB: number): boolean {
return this.find(elementA) === this.find(elementB);
}
/**
* Make elementA and elementB belong to the same set. Uses union by rank.
* @param {number} elementA The first element.
* @param {number} elementB The second element.
*/
union(elementA: number, elementB: number): void {
const rootA = this.find(elementA);
const rootB = this.find(elementB);
if (rootA === rootB) {
// Nothing to be done since elements already belong to the same set.
return;
}
// Reduce number of sets.
--this._size;
// Union by rank.
// Attaches the shorter tree to the root of the taller tree.
if (this._ranks[rootA] > this._ranks[rootB]) {
this._setSizes[rootA] += this._setSizes[rootB];
this._parents[rootB] = rootA;
return;
}
this._setSizes[rootB] += this._setSizes[rootA];
this._parents[rootA] = rootB;
if (this._ranks[rootA] === this._ranks[rootB]) {
++this._ranks[rootB];
}
}
}
export default DisjointSet;