최소 스패닝 트리를 공부하기 전에, 최소 스패닝 트리에 적용되는 서로소 집합에 대해서 공부한다.
1. 상호 배타적 집합(서로소 집합) ; Disjoint Set
- 공통 원소(혹은 공통 부분 집합)를 가지지 않는 집합, 교집합이 없는 집합들.
ex) { 1, 2, 3 } 과 { 4, 5, 6 } 은 서로소 집합이다.
(1) 유니온-파인드(Union-Find) 알고리즘
- 유니온 (Union) : 두 개의 서로소 집합을 하나로 합침.
- 파인드 (Find) : 주어진 원소를 가지는 집합을 찾음. 주어진 원소의 루트 노드를 찾는 것이 목표.
2. 트리 구조를 이용한 표현
class NaiveDisjointSet
{
public:
NaiveDisjointSet(int n) : _parent(n)
{
for (int i = 0; i < n; i++)
_parent[i] = i; // 자기의 부모는 자신
}
int Find(int u) // 루트 노드를 찾기
{
if (u == _parent[u]) // 찾는 u가 루트 노드임
return u;
return Find(_parent[u]); // 재귀적 호출로 위로 타고 올라가기
}
void Merge(int u, int v) // 합치기, u가 v 밑으로 들어감
{
u = Find(u); // u의 루트 노드 찾기
v = Find(v); // v의 루트 노드 찾기
if (u == v) // 예외 처리
return;
_parent[u] = v;
}
private:
vector<int> _parent;
};
단, 트리가 불균형하기 떄문에 이 코드는 그렇게 빨리 작동하지 않는다.
3. 랭크 최적화(균형 최적화) ; Rank Union(Balanced Union)
원소 개수가 적은 집합을 원소 개수가 많은 집합에 넣는 방식.
class NaiveDisjointSet
{
public:
NaiveDisjointSet(int n) : _parent(n), _rank(n, 1)
//~~~~~
//~~~~~
private:
vector<int> _parent;
vector<int> _rank;
};
클래스의 생성자에 _rank 맴버 변수를 받도록 설정한다.
void Merge(int u, int v) // 합치기, u가 v 밑으로 들어감
{
u = Find(u);
v = Find(v);
if (u == v) // 예외 처리
return;
if (_rank[u] > _rank[v])
swap(u, v);
// 항상 rank[u] <= rank[v] 이다
_parent[u] = v;
if (_rank[u] == _rank[v])
_rank[v]++;
}
트리의 높이가 같은 서로소 집합이 하나로 합쳐지면, 높이가 1 늘어난다(루트 노드의 아래로 들어가기 때문).
int Find(int u) // 루트 노드를 찾기
{
if (u == _parent[u]) // 찾는 u가 루트 노드임
return u;
return _parent[u] = Find(_parent[u]); // 재귀적 호출로 위로 타고 올라가기
}
Find 함수의 재귀적 호출 부분을 수정하면 찾는 속도를 최적화 할 수 있다.
'자료구조와 알고리즘 > 탐색 트리 & 최소 스패닝 트리' 카테고리의 다른 글
6-2. 최소 신장 트리(Minimum Spanning Tree), 크루스칼 알고리즘(Kruskal Algorithm) (0) | 2023.07.25 |
---|---|
4-5. 레드-블랙 트리(RBT ; Red-Black Tree) - (3) 데이터 삭제 구현 (0) | 2023.07.18 |
4-4. 레드-블랙 트리(RBT ; Red-Black Tree) - (2) 데이터 삭제 (0) | 2023.07.18 |
4-3. 레드-블랙 트리(RBT ; Red-Black Tree) - (1) (0) | 2023.07.18 |
4-2. 이진 탐색 트리(BST ; Binary Search Tree) (0) | 2023.07.14 |