유니온-파인드(Union-Find) 알고리즘은 여러 집합을 효율적으로 관리하는 데 사용되는 알고리즘이다. 주로 서로소 집합(disjoint-set)을 다루는 데에 활용된다. 유니온-파인드 알고리즘은 각 집합을 대표하는 원소를 찾거나, 두 집합을 합치는 등의 연산을 수행할 수 있다. 대표적으로 "합집합 찾기(Union)"와 "찾기(Find)" 연산이 있다.
간단한 버전
class UnionFind {
private final int[] parent;
public UnionFind(int size) {
this.parent = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i;
}
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootX] = rootY;
}
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
// 집합의 개수
public int countSets() {
int count = 0;
for (int i = 0; i < parent.length; i++) {
if (parent[i] == i) {
count++;
}
}
return count;
}
}
Rank사용 버전
rank 배열을 사용하여 각 집합의 랭크를 유지하고, 랭크를 비교하여 합치는 과정을 수행한다.
랭크가 낮은 트리를 높은 트리에 합치면서 트리의 높이를 최소화한다.
class UnionFind {
private int[] parent;
private int[] rank;
// 생성자: 초기화
public UnionFind(int size) {
parent = new int[size];
rank = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i; // 초기에는 각 원소가 자기 자신을 가리키도록 초기화
rank[i] = 0; // 초기에는 각 원소의 랭크가 0
}
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
// 두 집합의 루트가 같으면 이미 같은 집합에 속해 있는 것이므로 더 이상의 작업 필요 없음
if (rootX != rootY) {
// 랭크를 기준으로 더 낮은 랭크를 가진 집합을 높은 랭크를 가진 집합에 합침
if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else {
parent[rootX] = rootY;
rank[rootY]++;
}
}
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
}
집합의 사이즈를 관리하는 버전
class UnionFind {
private final int[] parent;
private final int[] size;
public UnionFind(int n) {
this.parent = new int[n];
this.size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
// y가 속한 집합 밑으로 새롭게 편입한다.
// y가 속한 집합에 부모를 x가 속합 집합에 부모로 한다.
parent[rootX] = rootY;
// y가 속합 집합의 크기를 x가 속한 집합의 크기와 더한다.
size[rootY] += size[rootX];
}
}
public int find(int x) {
// 혼자 속한 집합이 아니라면
if (parent[x] != x) {
// x가 속한 집합의 부모를 찾아서
// x의 부모로 한다. (경로 축소)
parent[x] = find(parent[x]);
}
return parent[x];
}
public int getSize(int x) {
int rootX = find(x);
return size[rootX];
}
}
728x90
'자료구조 & 알고리즘' 카테고리의 다른 글
위상 정렬 알고리즘 (0) | 2024.02.16 |
---|---|
퀵선택 알고리즘 (0) | 2024.02.15 |
단순 선택 정렬, 단순 삽입 정렬, 이진 삽입 정렬 (0) | 2023.12.12 |
버블 정렬, 칵테일 정렬 (0) | 2023.12.11 |
정렬 (0) | 2023.12.11 |