Skip to content

Commit ec709c1

Browse files
committed
quick find
1 parent 9e8f3e1 commit ec709c1

File tree

5 files changed

+173
-0
lines changed

5 files changed

+173
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Union - O(n)
2+
// Find - O(1)
3+
// Init - O(n)
4+
export class QuickFindUF {
5+
private id: number[];
6+
private size: number;
7+
8+
constructor(n: number) {
9+
this.size = n;
10+
this.id = new Array(n).fill(0).map((_, i) => i);
11+
}
12+
13+
public connected(p: number, q: number): boolean {
14+
return this.id[p] === this.id[q];
15+
}
16+
17+
public union(p: number, q: number): void {
18+
const newId = this.id[q];
19+
const previousId = this.id[p];
20+
21+
for(let i = 0; i < this.size; i++) {
22+
if (this.id[i] === previousId) {
23+
this.id[i] = newId;
24+
}
25+
}
26+
}
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Union - O(n)
2+
// Find - O(1)
3+
// Init - O(n)
4+
export class QuickUnionUF {
5+
private id: number[];
6+
private size: number;
7+
8+
constructor(n: number) {
9+
this.size = n;
10+
this.id = new Array(n).fill(0).map((_, i) => i);
11+
}
12+
13+
public connected(p: number, q: number): boolean {
14+
return this.root(p) === this.root(q);
15+
}
16+
17+
public union(p: number, q: number): void {
18+
const newId = this.id[q];
19+
const previousId = this.id[p];
20+
21+
for(let i = 0; i < this.size; i++) {
22+
if (this.id[i] === previousId) {
23+
this.id[i] = newId;
24+
}
25+
}
26+
}
27+
28+
private root(node: number): number {
29+
// chase parent pointers until reaches root
30+
while(this.id[node] !== node) node = this.id[node];
31+
return node;
32+
}
33+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Union - O(n)
2+
// Find - O(1)
3+
// Init - O(n)
4+
export class QuickUnionUF {
5+
private id: number[];
6+
private size: number;
7+
8+
constructor(n: number) {
9+
this.size = n;
10+
this.id = new Array(n).fill(0).map((_, i) => i);
11+
}
12+
13+
public connected(p: number, q: number): boolean {
14+
return this.root(p) === this.root(q);
15+
}
16+
17+
public union(p: number, q: number): void {
18+
const newId = this.id[q];
19+
const previousId = this.id[p];
20+
21+
for(let i = 0; i < this.size; i++) {
22+
if (this.id[i] === previousId) {
23+
this.id[i] = newId;
24+
}
25+
}
26+
}
27+
28+
private root(node: number): number {
29+
// chase parent pointers until reaches root
30+
while(this.id[node] !== node) {
31+
this.id[node] = this.id[this.id[node]]
32+
node = this.id[node];
33+
}
34+
return node;
35+
}
36+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Running Time
2+
// Find - takes time proportional to depth of p and q - lg N
3+
// Union - takes constant time, given roots, lg N
4+
// Depth of any node is at most lg N where lg = base-2 logarithm
5+
export class QuickUnionUF {
6+
private id: number[];
7+
private size: number;
8+
private nodeSize: number[];
9+
10+
constructor(n: number) {
11+
this.size = n;
12+
this.id = new Array(n).fill(0).map((_, i) => i);
13+
this.nodeSize = new Array(n).fill(0).map(() => 1);
14+
15+
}
16+
17+
public connected(p: number, q: number): boolean {
18+
return this.root(p) === this.root(q);
19+
}
20+
21+
public union(p: number, q: number): void {
22+
const i = this.id[q];
23+
const j = this.id[p];
24+
25+
for (let i = 0; i < this.size; i++) {
26+
if(this.nodeSize[i] < this.nodeSize[j]){
27+
this.id[i] = j;
28+
this.nodeSize[j] += this.nodeSize[i];
29+
} else {
30+
this.id[j] = i;
31+
this.nodeSize[i] += this.nodeSize[j];
32+
}
33+
}
34+
}
35+
36+
private root(node: number): number {
37+
// chase parent pointers until reaches root
38+
while (this.id[node] !== node) node = this.id[node];
39+
return node;
40+
}
41+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Union-Find
2+
3+
## Dynamic Connectivity
4+
5+
Given a set of n objects:
6+
7+
- Union command - connect two objects
8+
- Find / connected query - is there a path connecting two nodes?
9+
10+
## Quick-Find (eager approach)
11+
12+
- Integer array id[] of size N
13+
- Interpretation: p and q are connect if they have the same id.
14+
15+
## Quick Union
16+
17+
- Integer array id[] of size N
18+
- Interpretation:id[i] is parent of i.
19+
- Root of i is id[id[id[...id[i]...]]] ( keep going untill it doesnt change ) - algorithm ensures no cycle.
20+
- Find - Check if p and q have same root.
21+
- Union - To merge components containing p and q, set the id of p's root to the id of q's root.
22+
23+
## Quick Union Improvement - Weighing Quick-Union
24+
25+
- Modify quick-union to avoid tall trees.
26+
- keep track of size of each tree.
27+
- Balance by linking root of smaller tree to root of larger tree.
28+
29+
## Quic Union Improvement 2 - Path Compression
30+
31+
- Just after computing the root of p, set the id of each examined node to point to that root.
32+
33+
## Weighted Quick-Union with path compression
34+
35+
- Starting from an empty data structure, any sequence of M union-find ops on N objects makes =< c(N + Mlog*N) array access.
36+
- Analysis can be improved to N + M @a (M,N).

0 commit comments

Comments
 (0)