Union-Find
서로소 집합 (Disjoint-Set)을 표현할 때 사용하는 그래프 알고리즘
집합을 트리 구조로 표현하여 임의의 두 노드(원소)가 서로 같은 그래프(집합)에 속하는지 판별
Disjoint-Set
공통 원소가 없는 "상호 배타적인" 부분집합들로 나눠진 원소들에 대한 정보를 표현하는 자료구조
Unoin 연산과 Find 연산으로 이루어짐
- Union : 두 원소가 속한 집합을 하나로 합침
- Find : 해당 원소가 속한 집합(루트 원소)을 반환
Union-Find 사용 예시
- 특정 두 개체가 같은 그룹에 속하는지 효율적으로 판별하기 위해 사용됨
- 네트워크 연결 여부 판별
- 여러 개의 컴퓨터가 서로 연결될 떄, 특정 두 컴퓨터가 같은 네트워크에 속해 있는지 확인
- 최소 신장 트리 (MST) - 크루스칼 알고리즘
- 최소 비용으로 모든 노드를 연결하는 그래프를 만들 때 사이클이 생기지 않도록 검사
- 동일 집합 판별
- 여러 개의 요소가 있을 때, 특정 두 요소가 같은 그룹에 속하는지 판별
Union-Find 특징
- 각 집합을 하나의 트리로 나타내는 것이 핵심 → 트리의 특성에 따라 빠른 시간으로 탐색과 합치기가 가능
- 시간복잡도는 평균적으로 O(log N)이지만 편향될 경우 O(N)이 될 수 있음
- 이를 최적화하는 방법으로 경로 압축 (Path Compression), Rank 기반 연산이 있고 시간복잡도를 상수에 가깝게 만들 수 있음
Union-Find 기본 구현
1. initialize
: parent[x]를 자기 자신으로 초기화
int parent[MAX_SIZE];
void initialize() {
for(int x=0; x < MAX_SIZE; x++){
parent[x] = x;
}
}
2. Find
: Node x의 Root를 찾기
→ 재귀함수로 부모 노드가 자기 자신일 때까지 타고 올라감 (루트에 도달할 때까지)
int find(int x){
if (x == parent[x]) {
return x;
}
else return find(parent[x]);
}
3. Union
: Node a와 Node b를 합치기
→ b의 root를 부모 a의 root로 연결
void union(int a, int b){
int A = find(a);
int B = find(b);
if(A != B) {
parent[B] = A;
}
}
최적화 방법 - Path Compression
- find 연산 최적화
- find에서 root를 찾을 때 최악의 상황에서는 O(N)만큼의 계산이 요구됨
- find는 depth가 낮을 수록, 즉 트리의 높이가 낮을 수록 유리 !
- 매번 find 할 때 depth가 2 이상이면 Path Compression 수행

- 특징) Root node를 원하는 값으로 강제할 수 있음
int find(int x){
if(x == parent[x]) return x;
return parent[x] = find(parent[x]);
}
최적화 방법 - Rank
- union 연산 최적화
- rank에 트리의 높이(rank)를 저장하고, 항상 높이(rank)가 더 낮은 트리를 높은 트리 밑에 넣기

- 특징) union 과정을 역추적할 수 있음 (롤백 가능)
void union(int a, int b){
int A = find(a);
int B = find(b);
if(A == B) {
return;
}
if(rank[A] < rank[B]) {
parent[A] = B;
}
else if(rank[A] > rank[B]) {
parent[B] = A;
}
else {
parent[B] = A;
rank[A]++;
}
}
'알고리즘' 카테고리의 다른 글
| DP(다이나믹 프로그래밍) (0) | 2025.01.26 |
|---|---|
| 이분탐색 / Upper Bound / Lower Bound (0) | 2025.01.26 |
| 세그먼트 트리(Segment Tree) (0) | 2025.01.11 |
| JAVA 자료구조 (0) | 2025.01.11 |