어떤 문제를 푸는가
원소들이 여러 그룹으로 나뉘어 있고, 다음 두 연산을 빠르게 처리해야 합니다.
- Union(a, b) — a가 속한 그룹과 b가 속한 그룹을 합친다.
- Find(a) — a가 속한 그룹의 대표를 알려준다 (같은 그룹인지 비교용).
"두 도시가 연결되어 있는가?", "사이클이 생기는가?" 같은 동적 연결성 질문을
거의 상수 시간에 답하는 자료구조가 유니온 파인드(분리 집합, DSU)입니다.
기본 구조: 부모 포인터 숲
각 원소는 부모를 가리키는 parent 배열로 표현합니다. 루트는 자기 자신을
가리키며, 그 루트가 그룹의 대표입니다.
parent: 1→1 2→1 3→1 4→4 5→4
그룹: {1,2,3}, {4,5}
Find는 부모를 따라 루트까지 올라가고, Union은 한 루트를 다른 루트 밑에
붙입니다. 그냥 두면 트리가 한 줄로 길어져 Find가 \(O(N)\)이 될 수 있습니다.
두 가지 최적화로 이를 거의 상수로 만듭니다.
최적화 1 — 경로 압축 (Path Compression)
Find 도중 지나친 모든 정점을 루트에 직접 매답니다. 다음에 같은 정점을
찾을 땐 한 번에 루트에 도달합니다.
find(3): 3→1 ... 이후 3은 곧장 1을 가리킨다
최적화 2 — 합치기 기준 (Union by Rank / Size)
Union 시 작은 트리를 큰 트리 밑에 붙입니다. 그래야 높이가 천천히
자랍니다. 트리의 높이(rank)나 크기(size) 둘 중 하나를 기준으로 씁니다.
복잡도
두 최적화를 함께 쓰면 \(m\)번의 연산이
$$ O(m \cdot \alpha(N)) $$
에 처리됩니다. 여기서 \(\alpha\)는 역 아커만 함수 로, 현실의 모든 입력에서
\(\alpha(N) \le 4\) 입니다. 즉 사실상 연산당 상수 시간입니다. 경로 압축만, 혹은
랭크만 써도 \(O(\log N)\)은 보장되지만, 둘 다 쓰는 것이 표준입니다.
무엇을 표현할 수 있나
| 질문 | DSU로 보는 법 |
|---|---|
| 같은 그룹인가? | Find(a) == Find(b) |
| 그룹 수는? | 루트의 개수 |
| 그룹 크기는? | 루트에 size 저장 |
| 사이클이 생기나? | Union 전에 이미 같은 루트면 사이클 |
마지막 성질이 크루스칼 MST에서 핵심으로 쓰입니다. 다음 강의에서 구현과
대표 응용을 다룹니다.