Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8a4f117

Browse files
pschikAdministrator
and
Administrator
authored
merge: add UnionFind.js plus tests (#814)
* Create UnionFind.js * Create UnionFindTest.js * add UnionFind.js plus tests * implement PR comments * implement PR comment * fix codestyle Co-authored-by: Administrator <pi@pglp.noip.me>
1 parent 4fa3c5e commit 8a4f117

File tree

4 files changed

+185
-10943
lines changed

4 files changed

+185
-10943
lines changed

‎Search/UnionFind.js‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* union find data structure for javascript
3+
*
4+
* In computer science, a disjoint-set data structure, also called a union–find data structure or merge–find set,
5+
* is a data structure that stores a collection of disjoint (non-overlapping) sets. Equivalently, it stores a partition
6+
* of a set into disjoint subsets. It provides operations for adding new sets, merging sets (replacing them by their union),
7+
* and finding a representative member of a set.
8+
* The last operation allows to find out efficiently if any two elements are in the same or different sets.
9+
*
10+
* Disjoint-set data structures play a key role in Kruskal's algorithm for finding the minimum spanning tree of a graph.
11+
* The importance of minimum spanning trees means that disjoint-set data structures underlie a wide variety of algorithms.
12+
* In addition, disjoint-set data structures also have applications to symbolic computation, as well in compilers,
13+
* especially for register allocation problems.
14+
*
15+
* you can learn more on disjoint-set / union–find data structure at https://en.wikipedia.org/wiki/Disjoint-set_data_structure
16+
*/
17+
function UnionFind (n, key) {
18+
if (!(this instanceof UnionFind)) return new UnionFind(n)
19+
if (key && typeof key !== 'function') {
20+
throw new Error('key has to be a function or else left undefined')
21+
}
22+
let cnt, length
23+
// init Union Find with number of distinct groups. Each group will be referred to as index of the array of size 'size' starting at 0.
24+
// Provide an optional key function that maps these indices. I.e. for the groups starting with 1 provide function(a){return a-1;}. The default value is function(a){return a;}.
25+
key = key || function (a) { return a }
26+
cnt = length = n
27+
const id = new Array(n)
28+
const sz = new Array(n)
29+
for (let i = 0; i < n; i++) {
30+
id[i] = i
31+
sz[i] = 1
32+
}
33+
// Returns the number of elements of uf object.
34+
this.size = function () {
35+
return length
36+
}
37+
// Returns the number of distinct groups left inside the object.
38+
this.count = function () {
39+
return cnt
40+
}
41+
// Return the root (value) of the group in which p is.
42+
this.find = function (p) {
43+
p = key(p)
44+
while (p !== id[p]) {
45+
id[p] = id[id[p]]
46+
p = id[p]
47+
}
48+
return p
49+
}
50+
// Returns true if p and p are both in same group, false otherwise.
51+
this.connected = function (p, q) {
52+
p = key(p)
53+
q = key(q)
54+
ensureIndexWithinBounds(p, q)
55+
return this.find(p) === this.find(q)
56+
}
57+
// Combine elements in groups p and q into a single group. In other words connect the two groups.
58+
this.union = function (p, q) {
59+
p = key(p)
60+
q = key(q)
61+
ensureIndexWithinBounds(p, q)
62+
const i = this.find(p)
63+
const j = this.find(q)
64+
if (i === j) return
65+
if (sz[i] < sz[j]) {
66+
id[i] = j; sz[j] += sz[i]
67+
} else {
68+
id[j] = i; sz[i] += sz[j]
69+
}
70+
cnt--
71+
}
72+
function ensureIndexWithinBounds (args) {
73+
for (let i = arguments.length - 1; i >= 0; i--) {
74+
const p = arguments[i]
75+
if (p >= length) throw new Error('Index out of bounds. The maximum index can be length-1')
76+
}
77+
}
78+
}
79+
80+
export { UnionFind }

‎Search/test/UnionFind.test.js‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { UnionFind } from '../UnionFind'
2+
3+
const uf = new UnionFind(5)
4+
5+
test('should expose .size():', () => {
6+
const size = uf.size()
7+
expect(size).toBe(5)
8+
})
9+
10+
test('should do .union(num1, num2):', () => {
11+
uf.union(1, 2)
12+
uf.union(3, 4)
13+
uf.union(0, 4)
14+
expect(uf.connected(1, 2)).toBe(true)
15+
expect(uf.connected(1, 2)).toBe(true)
16+
17+
expect(uf.connected(3, 4)).toBe(true)
18+
expect(uf.connected(3, 0)).toBe(true)
19+
expect(uf.connected(4, 0)).toBe(true)
20+
21+
expect(uf.connected(1, 3)).toBe(false)
22+
expect(uf.connected(1, 4)).toBe(false)
23+
expect(uf.connected(1, 0)).toBe(false)
24+
expect(uf.connected(2, 3)).toBe(false)
25+
expect(uf.connected(2, 4)).toBe(false)
26+
expect(uf.connected(2, 0)).toBe(false)
27+
})
28+
29+
test('.count(), should return the number of disparate groups:', () => {
30+
expect(uf.count()).toBe(2)
31+
})
32+
33+
test('should check if two components are connected, .connected(num1, num2):', () => {
34+
expect(uf.connected(1, 2)).toBe(true)
35+
expect(uf.connected(1, 3)).toBe(false)
36+
})
37+
38+
test('should find the root of the tree in which the given element lives, .find(num):', () => {
39+
expect(uf.find(1)).toBe(1)
40+
expect(uf.find(2)).toBe(1)
41+
expect(uf.find(3)).toBe(3)
42+
expect(uf.find(4)).toBe(3)
43+
expect(uf.find(0)).toBe(3)
44+
})
45+
46+
test('should always change the id of the smaller tree and preserve the id of the larger one', () => {
47+
uf.union(2, 3)
48+
expect(uf.count()).toBe(1)
49+
expect(uf.find(0)).toBe(3)
50+
expect(uf.find(1)).toBe(3)
51+
expect(uf.find(2)).toBe(3)
52+
expect(uf.find(3)).toBe(3)
53+
expect(uf.find(4)).toBe(3)
54+
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /