Disjoint Set, 집합론에서 공통 원소가 없는 두 집합.
서로 다른 두 개의 집합을 병합하는 Union,
집합의 원소가 어떤 집합에 속해있는지 판단하는 Find.
각 원소에 대한 Find 함수 결과는 다음과 같다 ( Step3에서 병합)
public class Main {
static int[] parent; // 최상위 값을 저장하기 위함.
static int n = 5; // 5개라 가정
public static void main(String[] args) {
// Sample Test
// Step1. MakeSet
makeSet(n);
// Step2. Find
for (int i = 1; i <= n; ++i)
System.out.println("현재값 : " + i + ", 최상위 값 : " + parent[i]);
// Step3. Union
union(1, 2);
union(3, 4);
System.out.println();
// Step4. Find
for (int i = 1; i <= n; ++i)
System.out.println("현재값 : " + i + ", 최상위 값 : " + parent[i]);
}
private static void union(int a, int b) {
// 두 원소의 최상위 노드를 찾는다.
a = find(a);
b = find(b);
if (a != b) { // 최상위 노드가 다른경우, 합친다.
if (a > b)
parent[a] = b;
else
parent[b] = a;
}
}
private static int find(int n) {
if (parent[n] == n)
return n; // 최상위 값이 현재값과 같다면, 현재값 Return
else // 최상위 값이 현재와 다르다면, n은 다른 최상위 노드가 존재한다.
return parent[n] = find(parent[n]); // 경로 압축.
/*
* 경로 압축
* 경로 압축을 하지 않는다면, 트리구조의 하위 항목으로 계속 내려가게 된다.
* 하지만, Union-Find에서 중요한것은 현재의 Detph가 아닌 최상위 노드가 무엇인지를 찾는것이다.
* Depth를 깊게(세로로 긴 형태) 보다는 Width를 넓게 ( 가로로 긴 형태)로 만들자.
* 세로가 긴 형태는 O(n)에 수렴할 수 있다.
* 반면 가로가 긴 형태는 O(1)에 수렴한다.
*/
}
private static void makeSet(int n) {
parent = new int[n + 1];
for (int i = 1; i <= n; ++i)
parent[i] = i; // 최초 각 원소의 최상위 노드는 자기 자신이다.
}
}
#define N 5
#include<iostream>
using namespace std;
int parent[N + 1] = {};
int find(int n)
{
if (parent[n] == n)
return n;
else
return parent[n] = find(parent[n]);
}
void makeSet(int n)
{
for (int i = 1; i <= n; ++i) {
parent[i] = i;
}
}
void unionSet(int a, int b)
{
a = find(a);
b = find(b);
if (a != b)
{
if (a > b)
parent[a] = b;
else
parent[b] = a;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
// Step1. MakeSet
makeSet(N);
// Step2. Find
for (int i = 1; i <= N; ++i)
cout << "현재값 : " << i << ", 최상위 값 : " << parent[i] << endl;
// Step3. Union
unionSet(1, 2);
unionSet(3, 4);
cout << endl;
// Step4. Find
for (int i = 1; i <= N; ++i)
cout << "현재값 : " << i << ", 최상위 값 : " << parent[i] << endl;
return 0;
}