크루스칼 알고리즘의 모든 것: 이론부터 구현까지 완벽 해부
크루스칼 알고리즘의 모든 것: 이론부터 구현까지 완벽 해부
크루스칼 알고리즘은 컴퓨터 과학에서 중요한 최소 스패닝 트리(MST)를 찾는 대표적인 알고리즘 중 하나입니다. 이 글에서는 크루스칼 알고리즘의 개념, 동작 원리, 그리고 실제 코드 구현까지 다룹니다. 크루스칼 알고리즘은 간선 기반 알고리즘으로, 주로 많은 그래프 문제를 해결하는 데 사용됩니다.
크루스칼 알고리즘의 개요
크루스칼 알고리즘은 1956년에 최초로 소개되었습니다. 이 알고리즘은 그래프의 모든 간선
을 적은 비용 순으로 정렬한 후, 사이클이 형성되지 않도록 하나씩 간선을 추가하여 최소 스패닝 트리를 구성하는 방법입니다.
그래프 이론 배경
그래프(Graph)
: 정점(Vertex)과 간선(Edge)으로 구성된 데이터 구조입니다.스패닝 트리(Spanning Tree)
: 주어진 그래프의 모든 정점을 포함하는 트리입니다. 즉, 그래프의 부분집합으로 간선은 최소한으로 사용됩니다.최소 스패닝 트리(Minimum Spanning Tree, MST)
: 모든 정점을 연결하면서 전체 간선 가중치의 합이 최소인 스패닝 트리입니다.
크루스칼 알고리즘의 동작 원리
크루스칼 알고리즘은 다음과 같은 단계로 진행됩니다:
- 그래프의 모든 간선을 가중치 오름차순으로 정렬합니다.
- 간선을 하나씩 선택하면서, 현재 간선이 잇는 두 정점이 같은 트리에 속해 있지 않다면, 현재 간선을 최소 스패닝 트리에 추가합니다.
- 간선을 추가했을 때 사이클이 생기지 않도록 합니다. 이를 위해
Union-Find
자료구조를 사용합니다. - 모든 정점이 연결될 때까지 반복합니다.
크루스칼 알고리즘의 구현
이제 Python을 사용하여 크루스칼 알고리즘을 구현하는 방법을 살펴보겠습니다. 일반적으로 Union-Find 자료구조를 사용하여 사이클을 방지합니다.
필요한 함수 정의
- Union-Find 자료구조
pythonclass UnionFind: def __init__(self, n): self.parent = list(range(n)) self.rank = [0] * n def find(self, u): if self.parent[u] != u: self.parent[u] = self.find(self.parent[u]) return self.parent[u] def union(self, u, v): root_u = self.find(u) root_v = self.find(v) if root_u != root_v: if self.rank[root_u] > self.rank[root_v]: self.parent[root_v] = root_u elif self.rank[root_u] < self.rank[root_v]: self.parent[root_u] = root_v else: self.parent[root_v] = root_u self.rank[root_u] += 1
- 크루스칼 알고리즘 코어 함수
pythondef kruskal(n, edges): mst = [] uf = UnionFind(n) edges.sort(key=lambda x: x[2]) # 가중치 기준 오름차순 정렬 for u, v, weight in edges: if uf.find(u) != uf.find(v): uf.union(u, v) mst.append((u, v, weight)) return mst
예제 실행
이제 몇 가지 예제를 통해 크루스칼 알고리즘이 어떻게 작동하는지 살펴보겠습니다.
python# 정점 수와 간선 정보 n = 4 edges = [ (0, 1, 10), (0, 2, 6), (0, 3, 5), (1, 3, 15), (2, 3, 4) ] mst = kruskal(n, edges) print("Minimum Spanning Tree: ", mst)
위 예제에서는 4개의 정점과 5개의 간선이 주어졌으며, 이 간선들 중에서 최소 가중치를 갖는 스패닝 트리를 찾아 출력을 확인할 수 있습니다.
크루스칼 알고리즘의 시간 복잡도
크루스칼 알고리즘의 시간 복잡도는 O(E log E)
입니다. 여기서 E
는 그래프의 간선 수를 의미합니다. 이는 간선들을 정렬하는 데 필요한 시간에서 옵니다. 최악의 경우를 고려하더라도 크루스칼 알고리즘은 상당히 효율적이며, Union-Find 자료구조 덕분에 추가적인 최적화도 가능합니다.
결론
크루스칼 알고리즘은 그 단순성에도 불구하고 강력한 성능을 가진 알고리즘입니다. 최소 스패닝 트리를 쉽게 찾을 수 있고, 다양한 그래프 문제에서 활용될 수 있습니다. 이 글에서는 크루스칼 알고리즘의 이론적 배경부터 실제 코드 구현까지 자세히 다뤘으며, 이를 통해 적극적으로 문제를 해결하는 데 도움을 주고자 했습니다.