Data Structures & Algorithms

Dijkstra's Algorithm

Shortest paths from one vertex in a graph with non-negative weights, by repeatedly settling the closest unsettled vertex.

Level: advanced

What is it?

Dijkstra's algorithm computes the shortest distance from a source to every other vertex when all edge weights are non-negative. It keeps a tentative distance for each vertex and a priority queue ordered by distance. It repeatedly takes the closest unsettled vertex, whose distance is now final, and relaxes its outgoing edges: if going through it improves a neighbor's distance, update it.

Why does it matter?

Weighted shortest paths power maps, network routing, and scheduling. OSPF routers run Dijkstra's algorithm over the link-state database to build their forwarding tables, so it is where graph algorithms meet the networking section.

Mental model

Pouring water into a network of pipes from one point, where pipe length is travel time. The water reaches the nearest junction first, then the next nearest. The moment water arrives at a junction, that time is the shortest possible, because anything faster would already have arrived.

How it works

  • Greedy: always settle the unsettled vertex with the smallest known distance.
  • Relaxation: if dist[u] + w(u, v) < dist[v], update dist[v] and push it into the queue.
  • Correct only with non-negative weights: a negative edge can make a settled vertex improvable later.
  • With a binary heap, time is O((V + E) log V). Skip stale queue entries whose distance is already outdated.
  • Store predecessors to reconstruct the actual path, not just its length.
  • For negative weights use Bellman–Ford; for unweighted graphs plain BFS is enough.

Steps

  • Set the source distance to 0
  • Push it into a min-heap
  • Pop the closest vertex
  • Relax each outgoing edge
  • Repeat until the heap is empty

Code example: Shortest distances with a heap

import heapq

def dijkstra(graph, src):
    dist = {src: 0}
    pq = [(0, src)]
    while pq:
        d, u = heapq.heappop(pq)
        if d > dist.get(u, float("inf")):
            continue                        # stale queue entry
        for v, w in graph[u]:
            nd = d + w
            if nd < dist.get(v, float("inf")):
                dist[v] = nd
                heapq.heappush(pq, (nd, v))
    return dist

g = {"A": [("B", 4), ("C", 1)], "C": [("B", 2)], "B": []}
print(dijkstra(g, "A"))   # {'A': 0, 'B': 3, 'C': 1}

Complexity and trade-offs

Time: O((V + E) log V) with a binary heap

Space: O(V + E)

Trade-offs

  • Efficient for non-negative weights from a single source
  • Fails with negative edges
  • Computes distances to all vertices, even if you only need one

Real-world usage

  • OSPF and IS-IS link-state routing
  • Maps and navigation
  • Latency-based service routing and game AI pathfinding (often with A*)

Common mistakes

  • Using it on a graph with negative edge weights.
  • Forgetting to skip stale heap entries, so work is repeated.
  • Using a plain list as the frontier and getting O(V²) time without meaning to.

Interview questions

Why does Dijkstra's algorithm fail with negative edges?

It assumes that once a vertex is settled its distance is final, because any other route would be at least as long. A later negative edge could make a shorter route to a settled vertex, which the algorithm never revisits.

What is the complexity with a binary heap?

O((V + E) log V): each edge may cause a heap push, each push or pop costs O(log V), and there are at most E pushes.

How is Dijkstra used in networking?

Link-state protocols such as OSPF flood the topology to every router, and each router runs Dijkstra on its own copy to compute the shortest-path tree and the next hop for every destination.

Prerequisites

Related concepts

Continue learning

Browse the full computer science library