오늘은 지난번 섬 연결하기 문제에서 다뤘던 프림 알고리즘에 대해 알아보겠습니다. 프림 알고리즘이란?프림 알고리즘은 가중치가 있는 연결된 무향 그래프의 모든 꼭짓점을 포함하면서 각 변의 비용 합이 최소가 되는 부분 그래프인 트리, 즉 최소 비용 신장 트리(Minimum Spanning Tree)를 찾는 알고리즘입니다. 여기서 무향 그래프란 방향성이 없는 노드들이 연결되어있는 그래프 자료구조를 뜻합니다. 그래프의 자료구조 형태는 바로 아래 이미지와 같습니다. 즉, 무향 그래프는 두 노드간 방향성이 없고 연결에 대한 가중치만 있는 그래프입니다. 이 무향 그래프에서 모든 노드들을 연결하는데 있어 최소 비용의 합으로 연결되어진 최소 비용 신장 트리를 구하는 알고리즘 중 하나가 프림 알고리즘입니다. 프림 알고리즘의 개요는?프림 알고리즘은 아래 순서를 통해 무향 그래프에서 최소 비용의 합으로 모든 노드들을 연결하는 최소 비용 신장 트리를 구할 수 있습니다.
위 알고리즘이 종료되었을 때 만들어진 트리가 바로 최소 비용 신장 트리가 됩니다. 위에서 볼 수 있듯이 프림 알고리즘은 매 순간 최선의 조건을 선택하는 탐욕법(Greedy) 알고리즘을 바탕에 두는 점 참고하시기 바랍니다. 즉, 알고리즘의 3번에서 이미 연결된 트리와 연결되지 않은 가장 가중치가 낮은 선을 선택하는 것이 바로 순간의 최선의 조건을 선택한 것입니다. 프림 알고리즘의 동작은?위에 표현된 무향 그래프를 예로 프림 알고리즘을 통해 최소 비용 신장 트리(MST)를 구하는 동작을 설명하겠습니다. Step 1. 무향 그래프의 초기 그래프입니다. Step 2. 무향 그래프에서 Start 노드를 선택합니다. Step 3. Start 노드와 연결된 가장 가중치가 낮은 선을 선택하여 추가된 노드를 트리에 추가합니다. Step 4. Step 3에서 연결된 트리와 연결된 가장 가중치가 낮은 선을 선택하여 추가된 노드를 트리에 추가합니다. Step 5. 위에서 연결된 트리와 연결된 가장 가중치가 낮은 선을 선택하여 연결된 노드를 트리에 추가하는 동작을 반복합니다. 알고리즘이 종료되어 모든 노드가 연결된 트리, 최소 비용 신장 트리(MST)의 모습은 아래와 같습니다. 프림 알고리즘의 시간복잡도는?시간 복잡도는 간단하게 설명드리겠습니다. 프림 알고리즘에서 활용하는 최소 우선순위 큐를 구현할 수 있는 대표적인 자료구조가 두개(Binary Heap, Array) 있습니다. 이 자료구조를 어떤 것을 선택하느냐에 따라 시간 복잡도가 달라지기에 참고하시기 바랍니다.
무방향 가중치 그래프에서 최소 비용 신장 트리를 구하는 프림 알고리즘을 알아보았습니다. 내용적으로 어려운 부분은 제거하고 이해하기 쉽게 설명하는데 중점을 두었으니 더 심화적인 이해가 필요하신 분들은 아래 나열된 참고한 사이트를 참고하여 추가적인 학습을 진행하시기 바랍니다. 프림 알고리즘 학습 사이트
개요◎ 프림 알고리즘이란? ◎ 그림 예시 ◎ 구현 코드 - 인접 행렬 (Java) ◎ 시간 복잡도 - 인접 행렬 ◎ 구현 코드 - 힙 (Java) ◎ 시간 복잡도 - 힙 ◎ 특징 안녕하세요. J4J입니다. 이번 포스팅은 프림 알고리즘에 대해 적어보는 시간을 가져보려고 합니다. 프림 알고리즘이란?프림 알고리즘은 대표적인 MST 구현 알고리즘 중 하나로 정점을 기준으로 갈 수 있는 가중치가 가장 작은 길(간선)을 선택한 뒤 다음 정점을 방문하며 MST를 만드는 기법입니다. 예를 들어 A, B, C, D, E 정점이 있다고 가정해보겠습니다. A ↔ C 가중치: 3 A ↔ D 가중치: 5 B ↔ C 가중치: 4 B ↔ D 가중치: 4 C ↔ E 가중치: 2 D ↔ E 가중치: 1 이고 A 정점에서 출발한다면 다음과 같은 순서로 정점을 방문합니다. 1-1. A에서 갈 수 있는 정점을 확인합니다. (C: 3, D: 5) 1-2. 가장 작은 가중치를 가지는 C정점을 방문합니다. (방문 A, C) 2-1. C에서 갈 수 있는 정점을 확인합니다. (A: 3, B: 4, E: 2) 2-2. 이전에 방문했던 정점들의 가중치와 비교하여 방문하지 않은 정점들의 최솟값을 확인합니다. (B: 4, D: 5, E: 2) 2-3. 가장 작은 가중치를 가지는 E정점을 방문합니다. (방문 A, C, E) 3-1. E에서 갈 수 있는 정점을 확인합니다. (C: 2, D: 1) 3-2. 이전에 방문했던 정점들의 가중치와 비교하여 방문하지 않은 정점들의 최솟값을 확인합니다. (B: 4, D: 1) 3-3. 가장 작은 가중치를 가지는 D정점을 방문합니다. (방문 A, C, E, D) 4-1. D에서 갈 수 있는 정점을 확인합니다. (A: 5, B: 4, E: 1) 4-2. 이전에 방문했던 정점들의 가중치와 비교하여 방문하지 않은 정점들의 최솟값을 확인합니다. (B: 4) 4-3. 가장 작은 가중치를 가지는 B정점을 방문합니다. (방문 A, C, E, D, B) 5-1. 더 이상 방문할 수 있는 정점이 존재하지 않아 실행이 종료됩니다. 그림 예시위의 순서와 동일한 상황을 그림으로 표현해보겠습니다. (A: 0, B: 1, C: 2, D: 3, E: 4) 구현 코드 - 인접 행렬 (Java)
시간 복잡도 - 인접 행렬인접 행렬로 구현된 프림 알고리즘의 시간 복잡도는 O(N^2)입니다. while문 내부를 N만큼 순회를 하고 while문 내부에 있는 for문을 N만큼 순회하므로 N x N = N^2이라는 결과가 나옵니다. 구현 코드 - 힙 (Java)
시간 복잡도 - 힙힙으로 구현된 프림 알고리즘의 시간 복잡도는 O(ElogN)입니다. 여기서 E는 길(간선)의 개수의 총합을 의미합니다. while문 내부를 N만큼 순회하고 while문 내부에 있는 for문을 각 정점마다 연결되어 있는 길(간선)의 개수만큼 순회하기 때문에 N x 정점마다 연결되어 있는 길(간선)의 개수 = 길(간선)의 개수의 총합인 E가 됩니다. 그리고 for문 내부에 있는 우선순위 큐에 저장할 때 logN만큼의 시간이 사용됩니다. (우선순위 큐는 힙으로 구현되어 있고 힙에서 삽입을 위한 시간 복잡도는 logN입니다.) 결과적으로 E만큼 순회할 때 logN만큼의 시간이 더 존재하기 때문에 E x logN = ElogN라는 값이 나옵니다. (개인적으로 실제 값은 ElogN보다는 조금 더 큰 값이라고 생각합니다.) 특징1. 프림 알고리즘은 정점을 기준으로 구현되기 때문에 길(간선)의 개수가 많은 편일 때 주로 사용합니다. 2. 그리디(Greedy) 알고리즘 기법입니다. (각 상황별 가장 좋아 보이는 선택지를 고릅니다.) 정리● 프림 알고리즘은 가중치가 가장 작은 다른 정점을 선택하여 순회하는 MST 기법 ● 그리디 알고리즘이며 길(간선)의 개수가 많을 때 사용 ● 구현 방법은 인접 행렬과 힙이 존재 ● 인접 행렬의 시간 복잡도는 O(N^2), 힙의 시간 복잡도는 O(ElogN) ● 코드를 이해하기에는 인접 행렬이 더 효과적이라고 생각하는 편 이상으로 프림 알고리즘에 대해 간단하게 알아보는 시간이었습니다. 읽어주셔서 감사합니다. |