Publié · en amélioration
Guide Union-Find · 3/6
Ce chapitre n'est disponible qu'en anglais pour le moment.
In this chapter we write a Python DSU class with both path compression and union by size, and explain it line by line. Then we port the same core routine to C++, Java and TypeScript. All four versions treat elements as integers from 0 to n-1.
class DSU:
def __init__(self, n: int) -> None:
self.parent = list(range(n))
self.size = [1] * n
self.count = n
def find(self, x: int) -> int:
root = x
while self.parent[root] != root:
root = self.parent[root]
while self.parent[x] != root:
self.parent[x], x = root, self.parent[x]
return root
def union(self, a: int, b: int) -> bool:
ra, rb = self.find(a), self.find(b)
if ra == rb:
return False
if self.size[ra] < self.size[rb]:
ra, rb = rb, ra
self.parent[rb] = ra
self.size[ra] += self.size[rb]
self.count -= 1
return True
def connected(self, a: int, b: int) -> bool:
return self.find(a) == self.find(b)
def set_size(self, x: int) -> int:
return self.size[self.find(x)]self.parent = list(range(n)): every element points to itself, so we start with n singleton sets.self.size = [1] * n: the number of elements in each set. Only the value stored at a root is meaningful.self.count = n: the current number of sets, decremented on every successful merge.self.parent[x], x = root, self.parent[x] safely advances to the original parent.False; that return value is exactly what cycle detection needs.dsu = DSU(7)
edges = [(0, 1), (1, 2), (3, 4), (5, 6), (2, 0)]
for a, b in edges:
if not dsu.union(a, b):
print("edge closes a cycle:", (a, b)) # (2, 0)
print(dsu.count) # 3
print(dsu.connected(0, 2)) # True
print(dsu.set_size(4)) # 2#include <numeric>
#include <utility>
#include <vector>
struct DSU {
std::vector<int> parent, size;
int count;
explicit DSU(int n) : parent(n), size(n, 1), count(n) {
std::iota(parent.begin(), parent.end(), 0);
}
int find(int x) {
int root = x;
while (parent[root] != root) root = parent[root];
while (parent[x] != root) {
int next = parent[x];
parent[x] = root;
x = next;
}
return root;
}
bool unite(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return false;
if (size[ra] < size[rb]) std::swap(ra, rb);
parent[rb] = ra;
size[ra] += size[rb];
--count;
return true;
}
};union is a reserved word in C++, so the method is called unite.
public final class DSU {
private final int[] parent;
private final int[] size;
private int count;
public DSU(int n) {
parent = new int[n];
size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
count = n;
}
public int find(int x) {
int root = x;
while (parent[root] != root) root = parent[root];
while (parent[x] != root) {
int next = parent[x];
parent[x] = root;
x = next;
}
return root;
}
public boolean union(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return false;
if (size[ra] < size[rb]) { int t = ra; ra = rb; rb = t; }
parent[rb] = ra;
size[ra] += size[rb];
count--;
return true;
}
public int count() { return count; }
}export class DSU {
private parent: Int32Array;
private size: Int32Array;
count: number;
constructor(n: number) {
this.parent = Int32Array.from({ length: n }, (_, i) => i);
this.size = new Int32Array(n).fill(1);
this.count = n;
}
find(x: number): number {
let root = x;
while (this.parent[root] !== root) root = this.parent[root];
while (this.parent[x] !== root) {
const next = this.parent[x];
this.parent[x] = root;
x = next;
}
return root;
}
union(a: number, b: number): boolean {
let ra = this.find(a);
let rb = this.find(b);
if (ra === rb) return false;
if (this.size[ra] < this.size[rb]) [ra, rb] = [rb, ra];
this.parent[rb] = ra;
this.size[ra] += this.size[rb];
this.count--;
return true;
}
}The TypeScript version stores the arrays compactly in Int32Array. If your elements are strings, assign them numbers with a Map<string, number> first and reuse the same class.
A DSU needs only the parent and size arrays plus two methods, find and union. find locates the root with a loop and compresses the path; union hangs the smaller set under the larger one and reports whether a merge happened. The four implementations share the same structure, so once you understand one, the others read the same way.
0 commentaire
Se connecter · Connectez-vous pour laisser un commentaire.
Soyez le premier à commenter.