일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 최장 공통 부분 수열
- Strongly Sonnected Coponent
- 다이나믹 프로그래밍
- algorithm
- 크루스칼
- 플로이드 위셜
- 넘파이
- 우선순위 큐
- 트리
- 최소 스패닝 트리
- 강한 연결 요소
- graph
- 최단 거리
- 벨만 포드
- Longest Common Subsequence
- priority queue
- numpy
- 알고리즘
- minimum spanning tree
- 파이썬
- 최단 경로
- 우선 순위 큐
- python
- 그래프
- prim
- 최소 신장 트리
- tree
- 유니온 파인드
- traceback
- LCS
- Today
- Total
codinging
[알고리즘] Union Find 알아보기 본문
Union Find
유니온 파인드란 그래프의 관점에서 두 노드가 같은 그래프에 속하는지 빠르게 판별하는 알고리즘이다.
집합에서의 관점으로는 두 요소가 같은 집합에 속하는지 판별한다.
union find 알고리즘은 두 노드가 속하는 집합을 합치는 union 과 두 노드가 같은 집합인지 확인하는 find 연산이 있다.
설명
6개의 노드로 union find 의 예시를 들어보겠다.
부모를 알 수 있는 배열을 만드는데, 각 노드는 아직 아무 연결도 되어있지 않으므로 아직 자기자신이 부모이다.
1,2를 한 집합으로 4,5,6을 한 집합으로 묶고자 한다.
먼저 위의 예시는 잘못된 예시이다.
만약, 이런식으로 부모 노드를 연결한다면 문제가 생길 것 이다.
모든 노드를 연결 한다고 가정했을때 위와 같은 방식으로 부모노드를 연결한다면,
직접 연결된 노드를 찾는 것 과 다를 것 이 없기때문에 union find라는 알고리즘을 쓰는 이유가 없을 것 이다.
이제 옳은 예시를 보이겠다.
이런식으로 자식을 최 상위 부모를 연결 해준다.
1,2 와 4,5,6 그래프를 합친 경우이다.
각 노드(그래프)를 합치는 연산이 union(x,y) 이고
이 최상위 부모를 찾고 업데이트 해주는 연산이 find(x,y) 이다.
위 그래프는 parent를 나타내는 그래프이지, 실제 노드의 그래프 모양은 저것과 다르다.
예를 들어 union(2,5) 라 함은 노드2 와 노드5 를 합치는 것 이다.
하지만, parent그래프의 모양은 2와 5가 직접 연결 되지 않고 위와 같이 되는 것 이다.
이제 최적화 방법 까지 이용을 해서 구현을 할 것 이다.
단순 구현
// 초기화
int parent[MAX_SIZE];
for (int i = 0; i < MAX_SIZE; i++)
parent[i] = i;
int find(int x) {
if (parent[x] == x) { // 최상위 노드일때
return x;
} else {
// 부모 노드로 올라간다.
return find(parent[x]);
}
}
void union1(int x, int y){
// 각 노드가 속한 그래프의 최상위 노드를 찾는다.
x = find(x);
y = find(y);
// x가 포함된 그래프에 y가 포함된 그래프 연결
parent[y] = x;
}
find 최적화
union(5,6) -> union(4,5) -> union(3,4) -> union(2,3) -> union(1,2) 순으로 연결 한다면
위와 같은 그래프가 형성 될 것 이다.
위에서 말했듯이 이런식으로 형성 된다면 union find 알고리즘을 쓸 이유가 없기 때문에
find 연산에서 부모 노드로 올라가는 과정에서 각 노드의 부모를 업데이트 해 줌으로써 최적화가 가능하다
int find(int x) {
if (parent[x] == x) {
return x;
} else {
// 각 노드마다 부모 업데이트
return parent[x] = find(parent[x]);
}
}
union 최적화 & 전체 코드
union연산 최적화는 depth가 큰 그래프 밑에 depth가 작은 그래프를 붙이는 조건을 거는 것 으로 최적화가 가능하다.
int parent[MAX_SIZE];
int depth[MAX_SIZE]; // 트리의 깊이
for (int i = 0; i < MAX_SIZE; i++) {
parent[i] = i;
depth[i] = 1;
}
int find(int x) {
if (parent[x] == x) {
return x;
} else {
return parent[x] = find(parent[x]);
}
}
void union1(int x, int y){
x = find(x);
y = find(y);
// x == y 이면 x, y가 같은 그래프 라는 뜻
if(x == y)
return;
//depth가 깊은 그래프 밑에 depth 가 작은 그래프를 넣는다.
if(depth[x] < depth[y]) {
parent[x] = y;
}
else {
parent[y] = x;
if(depth[x] == depth[y])
depth[x]++; // 높이가 같으면 합친 후 깊이 + 1
}
}
'Algorithm' 카테고리의 다른 글
[알고리즘] 최단 경로 알고리즘 다익스트라(Dijkstra) 알아보기 (0) | 2023.07.10 |
---|---|
[알고리즘] MST(Minimum Spanning Tree) 최소 신장 트리, Kruskal, Prim Algorithm 알아보기 (2) | 2023.05.21 |
[알고리즘] 강한 연결 요소(Strongly Connected Component, SCC) 알아보기 (0) | 2023.04.09 |
[알고리즘] LCS(Longest Common Subsequence) 최장 공통 부분 수열 과 역추적(Trace Back) 알아보기 (1) | 2023.03.31 |