@thi.ng/adjacency 2.5.12 → 2.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/api.js +0 -1
- package/bfs.js +49 -79
- package/binary.js +93 -103
- package/dfs.js +40 -45
- package/disjoint-set.js +85 -95
- package/floyd-warshall.js +77 -99
- package/list.js +137 -134
- package/mst.js +13 -60
- package/package.json +14 -11
- package/sparse.js +161 -158
- package/utils.js +24 -22
package/CHANGELOG.md
CHANGED
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/bfs.js
CHANGED
|
@@ -1,85 +1,55 @@
|
|
|
1
1
|
import { BitField } from "@thi.ng/bitfield/bitfield";
|
|
2
2
|
import { DCons } from "@thi.ng/dcons/dcons";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
dist;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
dist.fill(0xffffffff);
|
|
33
|
-
dist[id] = 0;
|
|
34
|
-
marked.setAt(id);
|
|
35
|
-
while (queue.length) {
|
|
36
|
-
const v = queue.drop();
|
|
37
|
-
for (let n of graph.neighbors(v)) {
|
|
38
|
-
const c = dist[v] + cost(v, n);
|
|
39
|
-
if (c < dist[n] || !marked.at(n)) {
|
|
40
|
-
edges[n] = v;
|
|
41
|
-
dist[n] = c;
|
|
42
|
-
marked.setAt(n);
|
|
43
|
-
queue.push(n);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
3
|
+
class BFS {
|
|
4
|
+
graph;
|
|
5
|
+
marked;
|
|
6
|
+
edges;
|
|
7
|
+
dist;
|
|
8
|
+
constructor(graph, src, cost = () => 1) {
|
|
9
|
+
this.graph = graph;
|
|
10
|
+
const numV = graph.numVertices();
|
|
11
|
+
this.edges = new Uint32Array(numV);
|
|
12
|
+
this.dist = new Float32Array(numV);
|
|
13
|
+
this.marked = new BitField(numV);
|
|
14
|
+
this.search(src, cost);
|
|
15
|
+
}
|
|
16
|
+
search(id, cost) {
|
|
17
|
+
const queue = new DCons();
|
|
18
|
+
queue.prepend(id);
|
|
19
|
+
const { dist, edges, graph, marked } = this;
|
|
20
|
+
dist.fill(4294967295);
|
|
21
|
+
dist[id] = 0;
|
|
22
|
+
marked.setAt(id);
|
|
23
|
+
while (queue.length) {
|
|
24
|
+
const v = queue.drop();
|
|
25
|
+
for (let n of graph.neighbors(v)) {
|
|
26
|
+
const c = dist[v] + cost(v, n);
|
|
27
|
+
if (c < dist[n] || !marked.at(n)) {
|
|
28
|
+
edges[n] = v;
|
|
29
|
+
dist[n] = c;
|
|
30
|
+
marked.setAt(n);
|
|
31
|
+
queue.push(n);
|
|
46
32
|
}
|
|
33
|
+
}
|
|
47
34
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
path.prepend(id);
|
|
60
|
-
return path;
|
|
35
|
+
}
|
|
36
|
+
hasPathTo(id) {
|
|
37
|
+
return this.marked.at(id) !== 0;
|
|
38
|
+
}
|
|
39
|
+
pathTo(id) {
|
|
40
|
+
if (!this.marked.at(id))
|
|
41
|
+
return;
|
|
42
|
+
const { dist, edges } = this;
|
|
43
|
+
const path = new DCons();
|
|
44
|
+
for (; dist[id] > 0; id = edges[id]) {
|
|
45
|
+
path.prepend(id);
|
|
61
46
|
}
|
|
47
|
+
path.prepend(id);
|
|
48
|
+
return path;
|
|
49
|
+
}
|
|
62
50
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
* @remarks
|
|
69
|
-
* For repeated queries starting from the same `src` vertex, it's much better &
|
|
70
|
-
* faster to create an {@link BFS} instance to re-use internal state and use
|
|
71
|
-
* {@link BFS.pathTo} to check/obtain paths.
|
|
72
|
-
*
|
|
73
|
-
* By default all edges have an uniform cost, i.e. the overall path cost is
|
|
74
|
-
* topological distance.
|
|
75
|
-
*
|
|
76
|
-
* Reference:
|
|
77
|
-
* - https://en.wikipedia.org/wiki/Breadth-first_search
|
|
78
|
-
* - https://algs4.cs.princeton.edu/40graphs/
|
|
79
|
-
*
|
|
80
|
-
* @param graph -
|
|
81
|
-
* @param src -
|
|
82
|
-
* @param dest -
|
|
83
|
-
* @param cost -
|
|
84
|
-
*/
|
|
85
|
-
export const bfs = (graph, src, dest, cost) => new BFS(graph, src, cost).pathTo(dest);
|
|
51
|
+
const bfs = (graph, src, dest, cost) => new BFS(graph, src, cost).pathTo(dest);
|
|
52
|
+
export {
|
|
53
|
+
BFS,
|
|
54
|
+
bfs
|
|
55
|
+
};
|
package/binary.js
CHANGED
|
@@ -1,111 +1,101 @@
|
|
|
1
1
|
import { BitMatrix } from "@thi.ng/bitfield/bitmatrix";
|
|
2
2
|
import { __into, __invert, __toDot } from "./utils.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*edges() {
|
|
20
|
-
const directed = !this.undirected;
|
|
21
|
-
for (let i = this.mat.m; i-- > 0;) {
|
|
22
|
-
for (let n of this.neighbors(i)) {
|
|
23
|
-
if (directed || n > i) {
|
|
24
|
-
yield [i, n];
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
numEdges() {
|
|
30
|
-
return this.numE;
|
|
31
|
-
}
|
|
32
|
-
numVertices() {
|
|
33
|
-
return this.mat.m;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Resizes matrix to new size given.
|
|
37
|
-
*
|
|
38
|
-
* @param n - new max vertices
|
|
39
|
-
*/
|
|
40
|
-
resize(n) {
|
|
41
|
-
this.mat.resize(n);
|
|
42
|
-
return this;
|
|
43
|
-
}
|
|
44
|
-
addEdge(from, to) {
|
|
45
|
-
if (!this.mat.setAt(from, to, true)) {
|
|
46
|
-
this.numE++;
|
|
47
|
-
this.undirected && this.mat.setAt(to, from, true);
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
removeEdge(from, to) {
|
|
53
|
-
if (this.mat.setAt(from, to, false)) {
|
|
54
|
-
this.numE--;
|
|
55
|
-
this.undirected && this.mat.setAt(to, from, false);
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
hasEdge(from, to) {
|
|
61
|
-
return this.mat.at(from, to) !== 0;
|
|
62
|
-
}
|
|
63
|
-
hasVertex(id) {
|
|
64
|
-
return (this.mat.popCountRow(id) !== 0 || this.mat.popCountColumn(id) !== 0);
|
|
65
|
-
}
|
|
66
|
-
degree(id, type = "out") {
|
|
67
|
-
let degree = 0;
|
|
68
|
-
if (this.undirected || type !== "in")
|
|
69
|
-
degree += this.mat.popCountRow(id);
|
|
70
|
-
if (!this.undirected && type !== "out")
|
|
71
|
-
degree += this.mat.popCountColumn(id);
|
|
72
|
-
return degree;
|
|
73
|
-
}
|
|
74
|
-
neighbors(id) {
|
|
75
|
-
return [...this.mat.row(id, true).positions()];
|
|
76
|
-
}
|
|
77
|
-
similarity(id, threshold = 0) {
|
|
78
|
-
const mat = this.mat;
|
|
79
|
-
const query = mat.row(id, true);
|
|
80
|
-
const acc = [];
|
|
81
|
-
for (let i = 0, m = mat.m; i < m; i++) {
|
|
82
|
-
if (i === id)
|
|
83
|
-
continue;
|
|
84
|
-
const sim = query.similarity(mat.row(i, true));
|
|
85
|
-
if (sim >= threshold)
|
|
86
|
-
acc.push([i, sim]);
|
|
3
|
+
class AdjacencyBitMatrix {
|
|
4
|
+
mat;
|
|
5
|
+
undirected;
|
|
6
|
+
numE;
|
|
7
|
+
constructor(n, edges, undirected = false) {
|
|
8
|
+
this.mat = new BitMatrix(n);
|
|
9
|
+
this.undirected = undirected;
|
|
10
|
+
this.numE = 0;
|
|
11
|
+
edges && __into(this, edges);
|
|
12
|
+
}
|
|
13
|
+
*edges() {
|
|
14
|
+
const directed = !this.undirected;
|
|
15
|
+
for (let i = this.mat.m; i-- > 0; ) {
|
|
16
|
+
for (let n of this.neighbors(i)) {
|
|
17
|
+
if (directed || n > i) {
|
|
18
|
+
yield [i, n];
|
|
87
19
|
}
|
|
88
|
-
|
|
20
|
+
}
|
|
89
21
|
}
|
|
90
|
-
|
|
91
|
-
|
|
22
|
+
}
|
|
23
|
+
numEdges() {
|
|
24
|
+
return this.numE;
|
|
25
|
+
}
|
|
26
|
+
numVertices() {
|
|
27
|
+
return this.mat.m;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resizes matrix to new size given.
|
|
31
|
+
*
|
|
32
|
+
* @param n - new max vertices
|
|
33
|
+
*/
|
|
34
|
+
resize(n) {
|
|
35
|
+
this.mat.resize(n);
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
addEdge(from, to) {
|
|
39
|
+
if (!this.mat.setAt(from, to, true)) {
|
|
40
|
+
this.numE++;
|
|
41
|
+
this.undirected && this.mat.setAt(to, from, true);
|
|
42
|
+
return true;
|
|
92
43
|
}
|
|
93
|
-
|
|
94
|
-
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
removeEdge(from, to) {
|
|
47
|
+
if (this.mat.setAt(from, to, false)) {
|
|
48
|
+
this.numE--;
|
|
49
|
+
this.undirected && this.mat.setAt(to, from, false);
|
|
50
|
+
return true;
|
|
95
51
|
}
|
|
96
|
-
|
|
97
|
-
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
hasEdge(from, to) {
|
|
55
|
+
return this.mat.at(from, to) !== 0;
|
|
56
|
+
}
|
|
57
|
+
hasVertex(id) {
|
|
58
|
+
return this.mat.popCountRow(id) !== 0 || this.mat.popCountColumn(id) !== 0;
|
|
59
|
+
}
|
|
60
|
+
degree(id, type = "out") {
|
|
61
|
+
let degree = 0;
|
|
62
|
+
if (this.undirected || type !== "in")
|
|
63
|
+
degree += this.mat.popCountRow(id);
|
|
64
|
+
if (!this.undirected && type !== "out")
|
|
65
|
+
degree += this.mat.popCountColumn(id);
|
|
66
|
+
return degree;
|
|
67
|
+
}
|
|
68
|
+
neighbors(id) {
|
|
69
|
+
return [...this.mat.row(id, true).positions()];
|
|
70
|
+
}
|
|
71
|
+
similarity(id, threshold = 0) {
|
|
72
|
+
const mat = this.mat;
|
|
73
|
+
const query = mat.row(id, true);
|
|
74
|
+
const acc = [];
|
|
75
|
+
for (let i = 0, m = mat.m; i < m; i++) {
|
|
76
|
+
if (i === id)
|
|
77
|
+
continue;
|
|
78
|
+
const sim = query.similarity(mat.row(i, true));
|
|
79
|
+
if (sim >= threshold)
|
|
80
|
+
acc.push([i, sim]);
|
|
98
81
|
}
|
|
82
|
+
return acc.sort((a, b) => b[1] - a[1]);
|
|
83
|
+
}
|
|
84
|
+
invert() {
|
|
85
|
+
return __invert(
|
|
86
|
+
new AdjacencyBitMatrix(this.mat.n, void 0, this.undirected),
|
|
87
|
+
this.edges()
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
toString() {
|
|
91
|
+
return this.mat.toString();
|
|
92
|
+
}
|
|
93
|
+
toDot(ids) {
|
|
94
|
+
return __toDot(this.edges(), this.undirected, ids);
|
|
95
|
+
}
|
|
99
96
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
* false), creates symmetrical adjacencies.
|
|
106
|
-
*
|
|
107
|
-
* @param n - max vertices
|
|
108
|
-
* @param edges - edge pairs
|
|
109
|
-
* @param undirected -true, if undirected
|
|
110
|
-
*/
|
|
111
|
-
export const defAdjBitMatrix = (n, edges, undirected) => new AdjacencyBitMatrix(n, edges, undirected);
|
|
97
|
+
const defAdjBitMatrix = (n, edges, undirected) => new AdjacencyBitMatrix(n, edges, undirected);
|
|
98
|
+
export {
|
|
99
|
+
AdjacencyBitMatrix,
|
|
100
|
+
defAdjBitMatrix
|
|
101
|
+
};
|
package/dfs.js
CHANGED
|
@@ -1,50 +1,45 @@
|
|
|
1
1
|
import { BitField } from "@thi.ng/bitfield/bitfield";
|
|
2
2
|
import { DCons } from "@thi.ng/dcons/dcons";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
class DFS {
|
|
4
|
+
graph;
|
|
5
|
+
marked;
|
|
6
|
+
edges;
|
|
7
|
+
src;
|
|
8
|
+
constructor(graph, src) {
|
|
9
|
+
this.graph = graph;
|
|
10
|
+
this.src = src;
|
|
11
|
+
const numV = graph.numVertices();
|
|
12
|
+
this.edges = new Uint32Array(numV);
|
|
13
|
+
this.marked = new BitField(numV);
|
|
14
|
+
this.search(src);
|
|
15
|
+
}
|
|
16
|
+
search(id) {
|
|
17
|
+
const { edges, marked } = this;
|
|
18
|
+
marked.setAt(id);
|
|
19
|
+
for (let n of this.graph.neighbors(id)) {
|
|
20
|
+
if (!marked.at(n)) {
|
|
21
|
+
edges[n] = id;
|
|
22
|
+
this.search(n);
|
|
23
|
+
}
|
|
15
24
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return this.marked.at(id) !== 0;
|
|
28
|
-
}
|
|
29
|
-
pathTo(id) {
|
|
30
|
-
if (!this.marked.at(id))
|
|
31
|
-
return;
|
|
32
|
-
const { edges, src } = this;
|
|
33
|
-
const path = new DCons();
|
|
34
|
-
for (; id !== src; id = edges[id]) {
|
|
35
|
-
path.prepend(id);
|
|
36
|
-
}
|
|
37
|
-
path.prepend(id);
|
|
38
|
-
return path;
|
|
25
|
+
}
|
|
26
|
+
hasPathTo(id) {
|
|
27
|
+
return this.marked.at(id) !== 0;
|
|
28
|
+
}
|
|
29
|
+
pathTo(id) {
|
|
30
|
+
if (!this.marked.at(id))
|
|
31
|
+
return;
|
|
32
|
+
const { edges, src } = this;
|
|
33
|
+
const path = new DCons();
|
|
34
|
+
for (; id !== src; id = edges[id]) {
|
|
35
|
+
path.prepend(id);
|
|
39
36
|
}
|
|
37
|
+
path.prepend(id);
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* @param graph -
|
|
47
|
-
* @param src -
|
|
48
|
-
* @param dest -
|
|
49
|
-
*/
|
|
50
|
-
export const dfs = (graph, src, dest) => new DFS(graph, src).pathTo(dest);
|
|
41
|
+
const dfs = (graph, src, dest) => new DFS(graph, src).pathTo(dest);
|
|
42
|
+
export {
|
|
43
|
+
DFS,
|
|
44
|
+
dfs
|
|
45
|
+
};
|
package/disjoint-set.js
CHANGED
|
@@ -1,101 +1,91 @@
|
|
|
1
1
|
import { fillRange } from "@thi.ng/arrays/fill-range";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
class DisjointSet {
|
|
3
|
+
roots;
|
|
4
|
+
ranks;
|
|
5
|
+
count;
|
|
6
|
+
/**
|
|
7
|
+
* Creates new instance with `n` initial singular subsets.
|
|
8
|
+
*
|
|
9
|
+
* @param n - initial capacity, ID range [0..n)
|
|
10
|
+
*/
|
|
11
|
+
constructor(n) {
|
|
12
|
+
this.roots = fillRange(new Uint32Array(n));
|
|
13
|
+
this.ranks = new Uint8Array(n);
|
|
14
|
+
this.count = n;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns canonical ID (tree root) for given `id`. Unless `id`
|
|
18
|
+
* already is unified with some other ID, this will always return
|
|
19
|
+
* `id` itself (since each node is initially its own root).
|
|
20
|
+
*
|
|
21
|
+
* @param id - node ID
|
|
22
|
+
*/
|
|
23
|
+
canonical(id) {
|
|
24
|
+
const roots = this.roots;
|
|
25
|
+
while (id !== roots[id]) {
|
|
26
|
+
id = roots[id] = roots[roots[id]];
|
|
23
27
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Connects combines the trees of the given two node IDs and returns
|
|
32
|
+
* the new resulting canonical tree root ID.
|
|
33
|
+
*
|
|
34
|
+
* @param a - node ID
|
|
35
|
+
* @param b - node ID
|
|
36
|
+
*/
|
|
37
|
+
union(a, b) {
|
|
38
|
+
const rootA = this.canonical(a);
|
|
39
|
+
const rootB = this.canonical(b);
|
|
40
|
+
if (rootA === rootB) {
|
|
41
|
+
return rootA;
|
|
37
42
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*/
|
|
45
|
-
union(a, b) {
|
|
46
|
-
const rootA = this.canonical(a);
|
|
47
|
-
const rootB = this.canonical(b);
|
|
48
|
-
if (rootA === rootB) {
|
|
49
|
-
return rootA;
|
|
50
|
-
}
|
|
51
|
-
this.count--;
|
|
52
|
-
const ranks = this.ranks;
|
|
53
|
-
const ra = ranks[rootA];
|
|
54
|
-
const rb = ranks[rootB];
|
|
55
|
-
if (ra < rb) {
|
|
56
|
-
return (this.roots[rootA] = rootB);
|
|
57
|
-
}
|
|
58
|
-
ra === rb && ranks[rootA]++;
|
|
59
|
-
return (this.roots[rootB] = rootA);
|
|
43
|
+
this.count--;
|
|
44
|
+
const ranks = this.ranks;
|
|
45
|
+
const ra = ranks[rootA];
|
|
46
|
+
const rb = ranks[rootB];
|
|
47
|
+
if (ra < rb) {
|
|
48
|
+
return this.roots[rootA] = rootB;
|
|
60
49
|
}
|
|
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
|
-
|
|
50
|
+
ra === rb && ranks[rootA]++;
|
|
51
|
+
return this.roots[rootB] = rootA;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Returns true, if the given two nodes belong to the same tree /
|
|
55
|
+
* subset.
|
|
56
|
+
*
|
|
57
|
+
* @param a - node ID
|
|
58
|
+
* @param b - node ID
|
|
59
|
+
*/
|
|
60
|
+
unified(a, b) {
|
|
61
|
+
return this.canonical(a) === this.canonical(b);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns a `Map` of all subsets (connected components) with their
|
|
65
|
+
* canonical tree root IDs as keys and arrays of node IDs as values.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* If only the number of subsets is required, use the `count`
|
|
69
|
+
* property of this class instance instead (O(1), updated with each
|
|
70
|
+
* call to {@link DisjointSet.union}).
|
|
71
|
+
*/
|
|
72
|
+
subsets() {
|
|
73
|
+
const sets = /* @__PURE__ */ new Map();
|
|
74
|
+
const roots = this.roots;
|
|
75
|
+
for (let i = roots.length; i-- > 0; ) {
|
|
76
|
+
const id = this.canonical(i);
|
|
77
|
+
const s = sets.get(id);
|
|
78
|
+
if (s) {
|
|
79
|
+
s.push(i);
|
|
80
|
+
} else {
|
|
81
|
+
sets.set(id, [i]);
|
|
82
|
+
}
|
|
94
83
|
}
|
|
84
|
+
return sets;
|
|
85
|
+
}
|
|
95
86
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
export const defDisjointSet = (n) => new DisjointSet(n);
|
|
87
|
+
const defDisjointSet = (n) => new DisjointSet(n);
|
|
88
|
+
export {
|
|
89
|
+
DisjointSet,
|
|
90
|
+
defDisjointSet
|
|
91
|
+
};
|