Shortest Path Algorithms
Single-source and all-pairs: Dijkstra's greedy min-heap, Bellman-Ford negative edge relaxation and negative cycle detection, and Floyd-Warshall.
Reinforce your mental model: run, pause, and inspect live pointers with our interactive visualizer:
Shortest path algorithms resolve optimal routing across weighted relational networks under varying edge-weight regimes. From Dijkstra's greedy priority queue scans on non-negative edges to Bellman-Ford's cycle-detecting edge relaxations and Floyd-Warshall's all-pairs dynamic programming, routing algorithms balance mathematical guarantees against asymptotic efficiency.
1. Executive Summary & Learning Objectives
#The shortest path problem seeks a path between two vertices whose constituent edge weights sum to a minimum. Formulated by Edsger Dijkstra (1959), Richard Bellman (1958), Lester Ford (1956), and Robert Floyd (1962), the algorithms divide along two primary axes: Single-Source Shortest Path (SSSP) versus All-Pairs Shortest Path (APSP), and non-negative versus arbitrary negative edge weights.
By the end of this chapter, you will be able to:
- Implement Dijkstra's algorithm using a Min-Priority Queue, proving why non-negative edge weights are required for greedy finality.
- Execute the Bellman-Ford algorithm across relaxation passes, identifying negative weight cycles on the -th pass.
- Derive the Floyd-Warshall dynamic programming recurrence and explain why intermediate vertex must form the outermost loop.
- Trace Dijkstra's algorithm step-by-step using a structured state execution table tracking priority queue states and distance arrays.
- Select the appropriate shortest path strategy given network density, edge weight domains, and single-source versus all-pairs query contracts.
2. Edge Relaxation & The Triangle Inequality
#All shortest path algorithms rely on a fundamental operation: Edge Relaxation.
The Triangle Inequality
#For any vertices and source :
If the currently known distance to exceeds the path routed through , the estimate is relaxed:
| State | Relaxation Condition | Action Taken |
|---|---|---|
| Before Relaxation | Current distance , , edge . | Path through offers cost . |
| Relaxation Step | evaluates to true. | Update ; set . |
| After Relaxation | Invariant restored: . | holds an improved upper bound on true shortest distance. |
3. Dijkstra's Algorithm (Greedy Single-Source Shortest Path)
#Dijkstra's algorithm solves Single-Source Shortest Path (SSSP) on graphs with strictly non-negative edge weights ().
Algorithmic Invariant
#When a vertex with minimum tentative distance is extracted from the min-priority queue, its distance is final: .
Why Dijkstra Fails on Negative Edge Weights
#Dijkstra assumes that adding an edge to a path can never decrease its total length (). If an edge has negative weight (), an already "finalized" vertex could have its distance reduced by a longer path containing the negative edge, violating the greedy invariant.
export interface WeightedEdge {
to: number;
weight: number;
}
export function dijkstra(
adj: WeightedEdge[][],
numVertices: number,
source: number
): { distances: number[]; parents: (number | null)[] } {
const distances = new Float64Array(numVertices).fill(Infinity);
const parents = new Array<(number | null)>(numVertices).fill(null);
const visited = new Uint8Array(numVertices);
distances[source] = 0;
// Min-Priority Queue storing [distance, vertex]
// In production, use a Binary Heap priority queue
const pq: [number, number][] = [[0, source]];
while (pq.length > 0) {
// Extract minimum distance element
pq.sort((a, b) => a[0] - b[0]);
const [d, u] = pq.shift()!;
if (visited[u]) continue;
visited[u] = 1;
for (const edge of adj[u]) {
const v = edge.to;
const weight = edge.weight;
if (!visited[v] && distances[u] + weight < distances[v]) {
distances[v] = distances[u] + weight;
parents[v] = u;
pq.push([distances[v], v]);
}
}
}
return { distances: Array.from(distances), parents };
}4. Step-by-Step Worked Dry Run: Dijkstra's Algorithm
#Consider a directed weighted graph with 4 vertices , source vertex , and edges:
- ()
- ()
- ()
- ()
- ()
| Step | Extracted Vertex | Outgoing Edges Explored | Relaxation Check | Distance Array State After Step | Priority Queue State |
|---|---|---|---|---|---|
| 0 | — (Init) | None | None | [0, ∞, ∞, ∞] | [(0, 0)] |
| 1 | Node 0 () | () () | [0, 4, 1, ∞] | [(1, 2), (4, 1)] | |
| 2 | Node 2 () | () () | (Improved!) | [0, 3, 1, 6] | [(3, 1), (4, 1), (6, 3)] |
| 3 | Node 1 () | () | (Improved!) | [0, 3, 1, 4] | [(4, 3), (4, 1), (6, 3)] |
| 4 | Node 3 () | (No outgoing edges) | None | [0, 3, 1, 4] | [(4, 1), (6, 3)] |
| 5 | Stale Entries | Nodes already visited (visited[1]=1, visited[3]=1) | Skipped | [0, 3, 1, 4] | [] (Empty) |
Final Shortest Distances from Source 0: dist = [0, 3, 1, 4]. Shortest path to vertex : with total cost .
5. Bellman-Ford Algorithm (Negative Weights & Cycle Detection)
#Bellman-Ford solves SSSP in graphs that may contain negative edge weights, and formally determines whether the graph contains a Negative Weight Cycle.
The Relaxation Theorem
#In any graph with vertices, any simple shortest path contains at most edges.
Therefore, relaxing every edge in the graph times is mathematically guaranteed to find the true shortest distance to all reachable vertices.
The -th Negative Cycle Detection Pass
#If an additional -th pass over all edges succeeds in relaxing any edge (), a negative weight cycle exists! In a negative cycle, looping indefinitely drives path cost to .
export interface FlatEdge {
u: number;
v: number;
weight: number;
}
export function bellmanFord(
edges: FlatEdge[],
numVertices: number,
source: number
): { distances: number[] | null; hasNegativeCycle: boolean } {
const dist = new Float64Array(numVertices).fill(Infinity);
dist[source] = 0;
// Relax all edges V - 1 times
for (let i = 1; i < numVertices; i++) {
for (const edge of edges) {
if (dist[edge.u] !== Infinity && dist[edge.u] + edge.weight < dist[edge.v]) {
dist[edge.v] = dist[edge.u] + edge.weight;
}
}
}
// V-th pass: Detect negative weight cycles
for (const edge of edges) {
if (dist[edge.u] !== Infinity && dist[edge.u] + edge.weight < dist[edge.v]) {
return { distances: null, hasNegativeCycle: true };
}
}
return { distances: Array.from(dist), hasNegativeCycle: false };
}6. Floyd-Warshall Algorithm (All-Pairs Shortest Paths)
#Floyd-Warshall (1962) computes the shortest path between every pair of vertices via dynamic programming.
State Recurrence
#Let be the shortest distance from to utilizing only intermediate vertices from .
- Option 1: Path does not route through : Distance remains .
- Option 2: Path routes through : Distance becomes .
Critical Implementation Requirement: The intermediate vertex must unconditionally be the outermost loop! Inverting loop order computes invalid intermediate states.
export function floydWarshall(
matrix: number[][],
numVertices: number
): number[][] | null {
const dist: number[][] = matrix.map((row) => [...row]);
for (let k = 0; k < numVertices; k++) {
for (let i = 0; i < numVertices; i++) {
for (let j = 0; j < numVertices; j++) {
if (dist[i][k] !== Infinity && dist[k][j] !== Infinity) {
if (dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
}
// Check for negative weight cycles along the main diagonal
for (let i = 0; i < numVertices; i++) {
if (dist[i][i] < 0) return null; // Negative cycle detected!
}
return dist;
}7. Master Comparison of Shortest Path Algorithms
#| Algorithm | Problem Scope | Edge Weight Domain | Time Complexity | Auxiliary Space | Optimal Production Use Case |
|---|---|---|---|---|---|
| BFS | Single-Source (SSSP) | Unweighted () | Hop-count routing, social graph distance | ||
| Dijkstra | Single-Source (SSSP) | Non-negative only () | GPS map navigation, OSPF internet routing | ||
| Bellman-Ford | Single-Source (SSSP) | Arbitrary (Detects negative cycles) | Currency arbitrage detection, RIP network protocol | ||
| Floyd-Warshall | All-Pairs (APSP) | Arbitrary (Detects negative cycles) | Dense networks, transitive closure, small graphs () | ||
| Johnson's Algorithm | All-Pairs (APSP) | Arbitrary (Reweight via Bellman-Ford) | Sparse all-pairs shortest paths |
8. Common Traps, Edge Cases & Implementation Pitfalls
#- Infinity Arithmetic Overflow in Bellman-Ford / Floyd-Warshall:
- In languages with 32-bit signed integers (C++, Java), computing when causes integer underflow to negative values, corrupting shortest path distances. Guard all relaxations with
dist[u] !== Infinity.
- In languages with 32-bit signed integers (C++, Java), computing when causes integer underflow to negative values, corrupting shortest path distances. Guard all relaxations with
- Priority Queue Stale Pair Handling in Dijkstra:
- Standard priority queues without decrease-key support enqueue updated pairs. If
d > dist[u], the extracted pair is stale and must be immediately discarded (continue).
- Standard priority queues without decrease-key support enqueue updated pairs. If
- Loop Ordering in Floyd-Warshall:
- Writing instead of computes local paths through immediate neighbors rather than globally optimal paths through all intermediate vertices.
9. Real-World Applications & Practice Problems
#Production Systems
#- GPS Navigation (Google Maps, Waze): Augmented Dijkstra ( search) computes driving directions with road speed weight heuristics.
- Financial Arbitrage Engines: Bellman-Ford on negative-log currency exchange rate matrices detects risk-free arbitrage currency loops.
- Internet Protocol Routing (OSPF / BGP): Open Shortest Path First (OSPF) runs Dijkstra's algorithm inside autonomous systems to establish optimal packet routing tables.
Practice Problems
#- Network Delay Time (LeetCode 743) — Classic Dijkstra SSSP on weighted directed graphs.
- Cheapest Flights Within K Stops (LeetCode 787) — Bellman-Ford bounded by relaxation passes.
- Find the City With Smallest Number of Neighbors at Threshold (LeetCode 1334) — Floyd-Warshall all-pairs shortest paths.
10. References & Academic Attribution
#- Dijkstra, E. W. (1959). A note on two problems in connexion with graphs. Numerische Mathematik, 1(1), 269–271.
- Bellman, R. (1958). On a routing problem. Quarterly of Applied Mathematics, 16(1), 87–90.
- Ford, L. R. (1956). Network Flow Theory. Paper P-923. RAND Corporation.
- Floyd, R. W. (1962). Algorithm 97: Shortest path. Communications of the ACM, 5(6), 345.
- Warshall, S. (1962). A theorem on boolean matrices. Journal of the ACM (JACM), 9(1), 11–12.