[자료구조] 서로소 집합(Disjoint-Set)
1. 서로소 집합(Disjoint-Set)이란?
Disjoint-Set은 많은 서로소 부분 집합들로 나눠진 원소들에 대한 정보를 저장하고 조작하는 자료구조입니다.
Disjoint-Set은 두 가지 연산을 제공합니다.
- Find 연산: 어떤 원소가 주어졌을 때, 이 원소가 속한 집합을 반환합니다. 집합의 대표(representative)를 반환합니다.
- Union 연산: 두 개의 집합을 하나의 집합으로 합칩니다.
즉, 두 노드가 같은 그래프에 속하는지 판별하거나, 하나의 그래프로 합칠 때 사용할 수 있습니다.
아래와 같이 어떠한 연결도 없는 8개의 노드가 있다고 가정해보겠습니다.


보통 그래프라 하믄 여러 개의 노드들이 간선으로 연결되어 있는 그림을 떠올리실텐데, 위처럼 노드가 1개여도 그래프입니다.
즉, 위 그림은 현재 노드가 1개뿐인 8개의 그래프로 볼 수 있습니다. 각 그래프들은 현재 자기 자신만을 집합의 원소로 가지고 있죠.
당연히 각각의 노드는 자기가 속한 그래프의 원소가 자기 자신 밖에 없기 때문에 부모 노드로 자기 자신을 가집니다. 🙂
위 그래프에서 union(3, 4); union(7, 8)을 해주어 간선을 추가해보겠습니다.


위 표를 보면 4번 노드의 부모 노드가 3으로 바뀌었고, 8번 노드의 부모 노드가 7로 바뀌었습니다.
저는 Union(합침) 작업을 할 때는 작은 값이 기준이 되도록 했습니다. (부모노드가 되는 기준은 설정하기 나름이라고 생각합니다. 😉 )
다시 위 그래프에 간선을 추가해보겠습니다.


규칙이 보이시나요?
같은 그래프 내의 원소들은 동일한 부모노드를 가집니다 ! 😯
즉, 두 노드의 부모 노드가 누군지 찾아보면 두 노드가 같은 그래프에 속하는지 확인할 수 있게 됩니다. (Union-Find에서 Find 부분)
2. 코드
C 언어를 이용해서 Disjoint-Set의 두 연산들을 코드로 살펴보겠습니다.
union()
: 파라미터로 들어온 v2정점을 v1그래프로 합칩니다. (부모노드 값을 변경해주는 것만으로 간단히 해결하고 있습니다.)find()
: 입력으로 들어온 정점의 부모 노드를 구합니다.
boolean union(int v1, int v2) { v1 = find(v1); v2 = find(v2); if (v1 != v2) { parents[v2] = v1; return true; } return false; } int find(int v) { if (parents[v] == v) return v; return parents[v] = find(parents[v]); }
위 코드에서 find() 함수를 잠깐 살펴보겠습니다.
return parents[v] = find(..)로 재귀로 부른 가장 끝 부모 노드의 번호를 해당 그래프에 소속된 모든 노드의 부모로 세팅해주고 있습니다.
이를 Path Compression이라고 하는데 그림으로 살펴보면 다음과 같습니다.

위 그림에서 빨간색 테두리는 Find-Set 연산에서 파라미터로 넣은 지점을 표시하였습니다.
Find-Set 연산에서 return find();처럼 써주면 위 그림의 좌측과 같습니다.
Find-Set 연산에서 return parent[v] = find();처럼 써주면 위 그림의 우측과 같습니다.
즉, 그래프에 속한 모든 노드들의 부모노드로 바로 위에 있는 부모노드를 저장해두는 것이 아니라, 가장 끝에 있는 최종적인 부모 노드를 저장합니다. 그렇기 때문에 다음 Find-Set 연산을 할때는 재귀를 1번만 돌리면 부모를 바로 찾을 수 있게 됩니다.
3. 참고자료
[1] https://namu.wiki/w/Union Find
[2] https://blog.naver.com/ndb796/221230967614
[3] https://brenden.tistory.com/33
'Algorithm > Theory' 카테고리의 다른 글
[알고리즘] 최소비용 신장트리(MST) - Kruskal 알고리즘 (0) | 2019.12.12 |
---|---|
[자료구조] 그래프(Graph) (0) | 2019.12.10 |
[알고리즘] 동적 계획법(Dynamic Programming) (0) | 2019.10.24 |
[자료구조] 이분 그래프 (Bipartite Graph) (0) | 2019.09.24 |
[알고리즘] 백트래킹(Backtracking) (0) | 2019.09.02 |
댓글
이 글 공유하기
다른 글
-
[알고리즘] 최소비용 신장트리(MST) - Kruskal 알고리즘
[알고리즘] 최소비용 신장트리(MST) - Kruskal 알고리즘
2019.12.121. 최소비용 신장트리(MST, Minimum Spanning Tree)란? 먼저, 신장 트리(ST, Spanning Tree)는 사이클 없이 모든 노드를 연결하는 트리입니다. 모든 정점을 포함한다. 정점간 서로 연결되면서 사이클이 존재하지 않는 그래프이다. (트리의 조건이기도 하죠? 😉 틈새공부) 그래프에 여러 개의 신장 트리가 존재할 수 있는데, 이 중 간선의 가중치 합이 최소인 것을 최소비용 신장트리(MST)라 합니다. 2. Kruskal 알고리즘이란? Kruskal 알고리즘은 최소비용 신장트리(이하 MST)를 찾는 대표적인 알고리즘입니다. MST를 구하는 알고리즘으로 Prim 알고리즘도 있는데, Prim은 정점을 기준으로 한다면, Kruskal은 간선을 기준으로 합니다. 아래와 같은 그래프에서 M… -
[자료구조] 그래프(Graph)
[자료구조] 그래프(Graph)
2019.12.10그래프(Graph) 그래프란 연결되어 있는 객체 간의 관계를 표현하는 자료구조이다. 그래프의 종류는 크게 3가지로 나뉜다. 무방향 그래프(undirected graph) 방향 그래프(directed graph) 가중치 그래프(weighted graph) 더 넘어가기 전에, 그래프에서 알아야할 용어가 있다. 싸이클 분절점 위의 개념들을 익혔다면 그 다음으로 익혀야할 건 그래프의 탐색이다. 그래프에서 탐색은 가장 기본적인 연산이지만, 많은 문제들이 단순히 그래프의 노드를 탐색하는 것으로 해결될만큼 중요하다. 그래프의 탐색 방법은 2가지다. (2가지 밖에 없다 !) 깊이 우선 탐색(DFS : Depth First Search) 너비 우선 탐색(BFS : Breath First Search) DFS/BFS에 대… -
[알고리즘] 동적 계획법(Dynamic Programming)
[알고리즘] 동적 계획법(Dynamic Programming)
2019.10.241. 동적 계획법(Dynamic Programming, DP)이란? 동적 계획법(Dynamic Programming, DP)은 큰 문제를 작은 문제로 나눠서 푸는 알고리즘 설계 기법이다. 분할 정복 알고리즘과 차이는 메모이제이션의 필요여부다. 분할 정복 알고리즘은 계산된 소문제의 출력값을 저장하지 않는다. (1회용) 동적 계획법은 계산된 소문제의 출력값을 저장해서 다음 계산때 사용한다. (재활용) 동적 계획법을 적용시킬 수 있는 예시는 다음과 같다. f(a,b) = f(a-1,b) + f(a,b-1) (a,b >= 1 ) f(0,0) = 1, 임의의 자연수 n에 대해 f(n,0) = f(0,n) = 1 위 그림에서 초록색으로 칠해논 부분이 문제를 작은 문제로 분할하는 과정에서 중복되는 문제다. 그림의 패… -
[자료구조] 이분 그래프 (Bipartite Graph)
[자료구조] 이분 그래프 (Bipartite Graph)
2019.09.24이분 그래프란? 인접한 정점끼리 서로 다른 색으로 칠해서 모든 정점을 두 가지 색으로만 칠할 수 있는 그래프이다. 결과적으로 그래프의 모든 정점들이 두 개의 그룹으로 나눠진다. 해당 그래프가 이분 그래프인지 확인하기 위한 탐색 알고리즘으로 DFS와 BFS가 있다. #include #include using namespace std; int T; vector a[20001]; int color[20001]; // 인접한 정점이 서로 다른 색인지 구분하기 위해 1과 2의 값만 저장한다. void dfs(int node, int cnt) { color[node] = cnt; for (int i = 0; i < a[node].size(); i++) { int next = a[node][i]; if (color[…
댓글을 사용할 수 없습니다.