Prim's Algorithm
1. What is Prim's Algorithm?β
Prim's Algorithm is used to find the minimum spanning tree (MST) of a connected, undirected graph. It greedily selects vertices with the lowest distance to the current MST, adding them to the MST one by one.
2. Algorithm for Prim's Algorithmβ
- Start with an empty set to store the MST and a priority queue (min-heap) to store the vertices.
- Initialize a distance array to track the minimum weight edge connecting each vertex to the MST.
- Initialize all distances to infinity and set the distance of the starting vertex to 0.
- Repeat until all vertices are added to the MST:
- Extract the vertex with the minimum distance from the priority queue.
- Add the vertex to the MST.
- Update the distances of adjacent vertices if they are not already in the MST.
- The MST is formed by the edges connecting the vertices in the priority queue.
3. How Does Prim's Algorithm Work?β
- Prim's Algorithm greedily selects vertices with the lowest distance to the current MST, adding them to the MST one by one.
4. Problem Descriptionβ
Given a weighted, connected graph, Prim's Algorithm aims to find the minimum spanning tree (MST) of the graph.
5. Examplesβ
Example graph:
0 1 2 3
--------------------
0 | 0 2 0 6
1 | 2 0 3 8
2 | 0 3 0 0
3 | 6 8 0 0
6. Constraintsβ
- The graph must be connected and undirected.
- The weights of the edges can be positive or negative.
7. Implementationβ
Prim's Algorithmβ
- Python
- C++
- Java
- JavaScript
import heapq
def prim(graph):
min_heap = []
visited = set()
MST = []
start_vertex = list(graph.keys())[0]
visited.add(start_vertex)
for neighbor, weight in graph[start_vertex]:
heapq.heappush(min_heap, (weight, start_vertex, neighbor))
while min_heap:
weight, src, dest = heapq.heappop(min_heap)
if dest not in visited:
visited.add(dest)
MST.append((src, dest, weight))
for neighbor, weight in graph[dest]:
if neighbor not in visited:
heapq.heappush(min_heap, (weight, dest, neighbor))
return MST
#include <iostream>
#include <vector>
#include <queue>
#include <utility>
#include <unordered_set>
using namespace std;
typedef pair<int, int> pii;
vector<pii> prim(vector<vector<pii>>& graph) {
int V = graph.size();
vector<pii> MST;
priority_queue<pii, vector<pii>, greater<pii>> min_heap;
unordered_set<int> visited;
visited.insert(0); // Starting from vertex 0
for (auto& edge : graph[0])
min_heap.push({edge.second, edge.first, 0});
while (!min_heap.empty()) {
auto [weight, src, dest] = min_heap.top();
min_heap.pop();
if (visited.find(dest) == visited.end()) {
visited.insert(dest);
MST.push_back({src, dest});
for (auto& edge : graph[dest]) {
if (visited.find(edge.first) == visited.end())
min_heap.push({edge.second, dest, edge.first});
}
}
}
return MST;
}
import java.util.*;
class PrimAlgorithm {
static class Edge {
int dest, weight;
Edge(int dest, int weight) {
this.dest = dest;
this.weight = weight;
}
}
static List<Edge> primAlgorithm(List<List<Edge>> graph) {
int V = graph.size();
List<Edge> MST = new ArrayList<>();
PriorityQueue<Edge> minHeap = new PriorityQueue<>((a, b) -> a.weight - b.weight);
Set<Integer> visited = new HashSet<>();
visited.add(0); // Starting from vertex 0
for (Edge edge : graph.get(0))
minHeap.offer(edge);
while (!minHeap.isEmpty()) {
Edge edge = minHeap.poll();
int src = edge.dest;
int weight = edge.weight;
if (!visited.contains(src)) {
visited.add(src);
MST.add(edge);
for (Edge nextEdge : graph.get(src)) {
if (!visited.contains(nextEdge.dest))
minHeap.offer(nextEdge);
}
}
}
return MST;
}
}
class PriorityQueue {
constructor() {
this.heap = [];
}
push(item) {
this.heap.push(item);
this.heap.sort((a, b) => a[0] - b[0]);
}
pop() {
return this.heap.shift();
}
isEmpty() {
return this.heap.length === 0;
}
}
function prim(graph) {
const minHeap = new PriorityQueue();
const MST = [];
const visited = new Set();
const startVertex = Object.keys(graph)[0];
visited.add(startVertex);
for (const [neighbor, weight] of graph[startVertex]) {
minHeap.push([weight, startVertex, neighbor]);
}
while (!minHeap.isEmpty()) {
const [weight, src, dest] = minHeap.pop();
if (!visited.has(dest)) {
visited.add(dest);
MST.push([src, dest, weight]);
for (const [neighbor, weight] of graph[dest]) {
if (!visited.has(neighbor)) {
minHeap.push([weight, dest, neighbor]);
}
}
}
}
return MST;
}
8. Complexity Analysisβ
- Time Complexity: for a binary heap implementation, where is the number of edges and is the number of vertices.
- Space Complexity: for storing the graph and priority queue.
9. Advantages and Disadvantagesβ
Advantages:β
- Finds the minimum spanning tree of a graph efficiently.
- Works well with dense graphs.
Disadvantages:β
- Requires a priority queue, which can be expensive in terms of space and time.
- Not suitable for graphs with negative edge weights.