Skip to content
Part IA Lent Term

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 (w(u,v)0w(u, v) \ge 0 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 SS 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 uu has the smallest d[u]d[u] among all vertices still in the priority queue, its distance is final. Why? Any alternative path to uu must enter uu from some other unprocessed vertex xx. Since all edge weights are non-negative, the path via xx has cost at least d[x]+non-negatived[x]d[u]d[x] + \text{non-negative} \ge d[x] \ge d[u] (because uu was chosen as minimum). So d[u]d[u] cannot be improved.

Dijkstra algorithm worked example with final shortest-path distances

Worked Example

Same graph used in the Bellman-Ford notes: V={A,B,C,D,E,F,G}V = \{A,B,C,D,E,F,G\}, source s=Es = E, all weights non-negative.

Edges: EA:5E \to A:5, EF:7E \to F:7, EG:3E \to G:3, AB:1A \to B:1, AC:2A \to C:2, GF:3G \to F:3, CD:2C \to D:2.

IterExtractSd[A]d[A]d[B]d[B]d[C]d[C]d[D]d[D]d[E]d[E]d[F]d[F]d[G]d[G]
Init\emptyset\infty\infty\infty\infty0\infty\infty
1E{E}5\infty\infty\infty073
2G{E,G}5\infty\infty\infty063
3A{E,G,A}567\infty063
4B{E,G,A,B}567\infty063
5F{E,G,A,B,F}567\infty063
6C{E,G,A,B,F,C}5679063
7Dall5679063

Extract order (by minimum dd): E(0), G(3), A(5), B(6), F(6), C(7), D(9). Note that B and F both have d=6d=6; tie-breaking is arbitrary. At each step, the extracted vertex’s distance is final: no later relaxation can reduce it.

Shortest path from EE to DD: EACDE \to A \to C \to D (cost 5+2+2=95+2+2 = 9).

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 V=7|V| = 7 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 ImplementationEXTRACT-MINDECREASE-KEYTotal
Unsorted arrayO(V)O(V)O(1)O(1)O(V2+E)O(V^2 + E)
Binary heapO(logV)O(\log V)O(logV)O(\log V)O((V+E)logV)O((V+E)\log V)
Fibonacci heapO(logV)O(\log V) amortisedO(1)O(1) amortisedO(VlogV+E)O(V\log V + E)

Derivation for binary heap: V|V| EXTRACT-MIN at O(logV)O(\log V) each; up to E|E| DECREASE-KEY at O(logV)O(\log V) each. Total: O(VlogV+ElogV)=O((V+E)logV)O(|V|\log|V| + |E|\log|V|) = O((|V|+|E|)\log|V|).

For dense graphs where E=Θ(V2)|E| = \Theta(|V|^2), the array-based version (O(V2)O(|V|^2)) may outperform the binary heap version (O(V2logV)O(|V|^2 \log |V|)) due to lower constant factors. For sparse graphs, the heap methods are superior.

Comparison with Bellman-Ford

DijkstraBellman-Ford
Edge weightsw0w \ge 0 onlyAny real
TechniqueGreedy + PQDP / repeated relaxation
TimeO((V+E)logV)O((V+E)\log V)O(VE)O(VE)
Negative cycle detectionN/AYes
Works on DAGsYesYes

When Dijkstra Fails on Negative Edges

Consider sas \to a (weight 2), sbs \to b (weight 3), aba \to b (weight 2-2). Dijkstra from ss: extracts aa first (d[a]=2d[a]=2), marking it final. Then relaxes (a,b)(a,b): d[b]=2+(2)=0d[b] = 2 + (-2) = 0. But bb‘s distance is now 0, whereas aa was finalised at 2 — the true shortest distance to aa might actually be via bb if we could go backwards (in a graph with more edges). The algorithm cannot backtrack to correct aa, so it produces wrong results. Bellman-Ford correctly handles this case.

Summary

PropertyDetail
TypeGreedy algorithm
Weight constraintw(u,v)0w(u,v) \ge 0 for all edges
Data structurePriority queue (min-heap)
Invariantv.d=δ(s,v)v.d = \delta(s,v) for all vSv \in S
Binary heap timeO((V+E)logV)O((V+E)\log V)
Fibonacci heap timeO(VlogV+E)O(V\log V + E)
Fails onNegative edge weights

Past paper questions: y2024p1q9 (opportunities, Dijkstra variants), y2023p1q9 (bidirectional Dijkstra), y2025p1q10(d) (Dijkstra with different priority queues).