Prim's Algorithm
Algorithm · Stretch
Step through it: Weighted Shortest Path pattern
Step 1 of 6
Goal: the cheapest route from A to every place when roads have different costs: A→B 4, A→C 1, C→B 2, B→D 1. Keep a table of the best known cost to each place: 0 for A, unknown for the rest.
Step 2 of 6
Always finish the closest unfinished place first: A (cost 0). Try its roads: B costs 0 + 4 = 4 and C costs 0 + 1 = 1.
Step 3 of 6
The closest unfinished place is now C (1). The road C→B gives B a cost of 1 + 2 = 3, cheaper than 4, so update B.
Step 4 of 6
Closest unfinished: B (3). The road B→D gives D a cost of 3 + 1 = 4.
Step 5 of 6
The cheapest A to D is 4, via A, C, B, D. Finishing the closest place first guarantees no later road can beat it, as long as no cost is negative. A priority queue finds the closest place quickly. This is Dijkstra's algorithm.
Step 6 of 6
Your turn.
In computer science, Prim's algorithm is a greedy algorithm that finds a minimum spanning tree for a weighted undirected graph.
The algorithm operates by building this tree one vertex at a time, from an arbitrary starting vertex, at each step adding the cheapest possible connection from the tree to another vertex.
Prim's algorithm starting at vertex A. In the third step, edges
BD and AB both have weight 2, so BD is chosen arbitrarily.
After that step, AB is no longer a candidate for addition
to the tree because it links two nodes that are already
in the tree.
Minimum Spanning Tree
A minimum spanning tree (MST) or minimum weight spanning tree is a subset of the edges of a connected, edge-weighted (un)directed graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight. That is, it is a spanning tree whose sum of edge weights is as small as possible. More generally, any edge-weighted undirected graph (not necessarily connected) has a minimum spanning forest, which is a union of the minimum spanning trees for its connected components.
A planar graph and its minimum spanning tree. Each edge is labeled with its weight, which here is roughly proportional to its length.
This figure shows there may be more than one minimum spanning tree in a graph. In the figure, the two trees below the graph are two possibilities of minimum spanning tree of the given graph.
Code
import Graph from '../../../data-structures/graph/Graph';
import PriorityQueue from '../../../data-structures/priority-queue/PriorityQueue';
/**
* @param {Graph} graph
* @return {Graph}
*/
export default function prim(graph) {
// It should fire error if graph is directed since the algorithm works only
// for undirected graphs.
if (graph.isDirected) {
throw new Error('Prim\'s algorithms works only for undirected graphs');
}
// Init new graph that will contain minimum spanning tree of original graph.
const minimumSpanningTree = new Graph();
// This priority queue will contain all the edges that are starting from
// visited nodes and they will be ranked by edge weight - so that on each step
// we would always pick the edge with minimal edge weight.
const edgesQueue = new PriorityQueue();
// Set of vertices that has been already visited.
const visitedVertices = {};
// Vertex from which we will start graph traversal.
const startVertex = graph.getAllVertices()[0];
// Add start vertex to the set of visited ones.
visitedVertices[startVertex.getKey()] = startVertex;
// Add all edges of start vertex to the queue.
startVertex.getEdges().forEach((graphEdge) => {
edgesQueue.add(graphEdge, graphEdge.weight);
});
// Now let's explore all queued edges.
while (!edgesQueue.isEmpty()) {
// Fetch next queued edge with minimal weight.
/** @var {GraphEdge} currentEdge */
const currentMinEdge = edgesQueue.poll();
// Find out the next unvisited minimal vertex to traverse.
let nextMinVertex = null;
if (!visitedVertices[currentMinEdge.startVertex.getKey()]) {
nextMinVertex = currentMinEdge.startVertex;
} else if (!visitedVertices[currentMinEdge.endVertex.getKey()]) {
nextMinVertex = currentMinEdge.endVertex;
}
// If all vertices of current edge has been already visited then skip this round.
if (nextMinVertex) {
// Add current min edge to MST.
minimumSpanningTree.addEdge(currentMinEdge);
// Add vertex to the set of visited ones.
visitedVertices[nextMinVertex.getKey()] = nextMinVertex;
// Add all current vertex's edges to the queue.
nextMinVertex.getEdges().forEach((graphEdge) => {
// Add only vertices that link to unvisited nodes.
if (
!visitedVertices[graphEdge.startVertex.getKey()]
|| !visitedVertices[graphEdge.endVertex.getKey()]
) {
edgesQueue.add(graphEdge, graphEdge.weight);
}
});
}
}
return minimumSpanningTree;
}References
Practice
Weighted Shortest Path
- Network Delay TimeMedium
- Cheapest Flights Within K StopsMedium
- Path With Minimum EffortMedium
- Path with Maximum ProbabilityMedium
- Find the City With the Smallest Number of NeighborsMedium
- Minimum Cost to Reach Destination in TimeMedium
- Swim in Rising WaterHard
- Minimum Cost to Make at Least One Valid Path in a GridHard
Greedy
- Assign CookiesEasy
- Lemonade ChangeEasy
- Best Time to Buy and Sell Stock IIEasy
- Can Place FlowersEasy
- Jump GameMedium
- Jump Game IIMedium
- Gas StationMedium
- Hand of StraightsMedium
- Task SchedulerMedium
- Queue Reconstruction by HeightMedium
- Partition LabelsMedium
- Maximum SubarrayMedium
- CandyHard
- Minimum Number of Taps to Open to Water a GardenHard
Spotted a mistake or something unclear? Report it on GitHub.