Dijkstra's Algorithm
Overview
Dijkstra’s algorithm solves the single-source shortest paths (SSSP) problem for directed or undirected graphs with non-negative edge weights ( for all edges). It is a greedy algorithm: at each step, it selects the unprocessed vertex with the smallest current distance estimate, finalises it, and relaxes its outgoing edges.
Pseudocode
DIJKSTRA(G, w, s):
for each v in G.V:
v.d = ∞
v.π = NIL
s.d = 0
S = ∅ // set of finalised vertices
Q = new PriorityQueue(G.V) // keyed on v.d
while Q not empty:
u = EXTRACT-MIN(Q)
S = S ∪ {u}
for each v in G.Adj[u]:
RELAX(u, v, w) // may call DECREASE-KEY on Q
The set tracks finalised vertices. It is not required for execution (the priority queue alone determines which vertex is processed next), but it is used in the correctness proof.
Greedy Intuition
Once a vertex has the smallest among all vertices still in the priority queue, its distance is final. Why? Any alternative path to must enter from some other unprocessed vertex . Since all edge weights are non-negative, the path via has cost at least (because was chosen as minimum). So cannot be improved.
Worked Example
Same graph used in the Bellman-Ford notes: , source , all weights non-negative.
Edges: , , , , , , .
| Iter | Extract | S | |||||||
|---|---|---|---|---|---|---|---|---|---|
| Init | — | 0 | |||||||
| 1 | E | {E} | 5 | 0 | 7 | 3 | |||
| 2 | G | {E,G} | 5 | 0 | 6 | 3 | |||
| 3 | A | {E,G,A} | 5 | 6 | 7 | 0 | 6 | 3 | |
| 4 | B | {E,G,A,B} | 5 | 6 | 7 | 0 | 6 | 3 | |
| 5 | F | {E,G,A,B,F} | 5 | 6 | 7 | 0 | 6 | 3 | |
| 6 | C | {E,G,A,B,F,C} | 5 | 6 | 7 | 9 | 0 | 6 | 3 |
| 7 | D | all | 5 | 6 | 7 | 9 | 0 | 6 | 3 |
Extract order (by minimum ): E(0), G(3), A(5), B(6), F(6), C(7), D(9). Note that B and F both have ; tie-breaking is arbitrary. At each step, the extracted vertex’s distance is final: no later relaxation can reduce it.
Shortest path from to : (cost ).
Comparison with Bellman-Ford on the Same Graph
Bellman-Ford takes up to 7 iterations of relaxing all edges. On this graph it converges in 2 iterations (since the longest shortest path has 3 edges, but convergence can be faster depending on edge order). Dijkstra extracts exactly vertices, each with one priority queue extract-min and neighbour relaxation. The extra overhead of the priority queue is offset by not scanning all edges on every iteration.
Running Time Analysis
Depends on the priority queue implementation:
| PQ Implementation | EXTRACT-MIN | DECREASE-KEY | Total |
|---|---|---|---|
| Unsorted array | |||
| Binary heap | |||
| Fibonacci heap | amortised | amortised |
Derivation for binary heap: EXTRACT-MIN at each; up to DECREASE-KEY at each. Total: .
For dense graphs where , the array-based version () may outperform the binary heap version () due to lower constant factors. For sparse graphs, the heap methods are superior.
Comparison with Bellman-Ford
| Dijkstra | Bellman-Ford | |
|---|---|---|
| Edge weights | only | Any real |
| Technique | Greedy + PQ | DP / repeated relaxation |
| Time | ||
| Negative cycle detection | N/A | Yes |
| Works on DAGs | Yes | Yes |
When Dijkstra Fails on Negative Edges
Consider (weight 2), (weight 3), (weight ). Dijkstra from : extracts first (), marking it final. Then relaxes : . But ‘s distance is now 0, whereas was finalised at 2 — the true shortest distance to might actually be via if we could go backwards (in a graph with more edges). The algorithm cannot backtrack to correct , so it produces wrong results. Bellman-Ford correctly handles this case.
Summary
| Property | Detail |
|---|---|
| Type | Greedy algorithm |
| Weight constraint | for all edges |
| Data structure | Priority queue (min-heap) |
| Invariant | for all |
| Binary heap time | |
| Fibonacci heap time | |
| Fails on | Negative edge weights |
Past paper questions: y2024p1q9 (opportunities, Dijkstra variants), y2023p1q9 (bidirectional Dijkstra), y2025p1q10(d) (Dijkstra with different priority queues).