Free beta: 60 days of full access, no card needed.84 seats leftSign up free

We use necessary cookies to run the site (sign-in and language). If you accept, we also load Google Analytics to see which pages are used, and Google reCAPTCHA to keep spam off the contact and bug-report forms. Privacy policy

← Blog
How to prepare

Dijkstra's algorithm in Python: shortest paths with a heap in O((V + E) log V)

· 2026-10-11 ·

Short answer. Dijkstra's algorithm finds the shortest path from one node to every other node. Edge weights must be non-negative. It pops the closest open node from a heap and relaxes its neighbours. Time O((V + E) log V). Below: the trigger words, Python code, a traced run and Network Delay Time.

What does Dijkstra's algorithm do?

You have a graph where every edge has a weight. You want the cheapest route from the start to each other node.

Breadth-first search counts edges. It only works when every edge costs the same. Dijkstra handles weights, as long as none is negative.

The idea: always take the closest node not yet settled. Its distance cannot improve any more. Use it to improve its neighbours. That improvement step is called relaxing an edge.

Shortest distances with Dijkstra
dijkstra(6, [[[1, 4], [2, 1]], [[3, 1]], [[1, 2], [3, 5]], [[4, 3], [5, 6]], [[5, 1]], []], 0)
number above a node = best known distance from 0
heap as [distance, node], nearest first
front →[0, 0]

Find the shortest distance from node 0 to every node. Every distance starts at ∞, node 0 gets 0 and goes into the heap.

Speed race
Bellman-Ford and Dijkstra on the same weighted graph of 16 nodes

Bars: the current distance from node 0 to each node. A full-height bar means the node is not reached yet.

One operation is one edge check or one step inside the heap. Every frame, each lane does the same number of operations, so the slow one falls behind.

Bellman-Ford O(V·E)
0 operations
Dijkstra with a heap O(E log V)
0 operations

 

And with more numbers

Operations for n numbers, and roughly how long they take at 100 million simple operations a second. An estimate from the same count, not a measurement.

n = 1,000
Bellman-Ford2M · 20 ms
Dijkstra with a heap14K · under 1 ms
n = 100,000
Bellman-Ford20B · 3.3 min
Dijkstra with a heap2.2M · 22 ms
n = 10,000,000
Bellman-Ford200T · 23 days
Dijkstra with a heap299M · 3 s

The pattern page: when to use it, and a template in six languages

When does a problem need Dijkstra's algorithm?

  • "Shortest path", "minimum cost", "minimum time".
  • "Weighted graph" with non-negative weights.
  • "Grid where each cell has an entry cost."
  • "How long until a signal reaches every node."

All weights equal to one: use BFS. Negative weights: use Bellman-Ford. Dijkstra sits between the two.

How does the algorithm work step by step?

  • Distance to the start is 0, to everything else infinity.
  • Push (0, start) onto a min-heap.
  • Pop the pair with the smallest distance. If it is larger than the known distance, skip it.
  • For each neighbour compute a new distance. If it is smaller than the stored one, store it and push.
  • Heap empty: all distances are final.

The skip step is lazy deletion. Stale pairs stay in the heap and get ignored when they surface.

What does one run of Dijkstra's algorithm look like?

Nodes A, B, C, D. Edges: A-B weight 1, A-C weight 4. Also B-C weight 2 and C-D weight 1. Start at A.

Pop A at 0. B becomes 1, C becomes 4. Pop B at 1. Through B, C becomes 3, better than 4, update. Pop C at 3. D becomes 4. Pop the stale (4, C) and skip it. Pop D. Result: A 0, B 1, C 3, D 4.

How do you write Dijkstra's algorithm in Python?

import heapq

def dijkstra(graph, start):
    # graph: {node: [(neighbour, weight), ...]}
    dist = {v: float("inf") for v in graph}
    dist[start] = 0
    heap = [(0, start)]

    while heap:
        d, v = heapq.heappop(heap)
        if d > dist[v]:
            continue                  # stale entry
        for u, w in graph[v]:
            nd = d + w
            if nd < dist[u]:
                dist[u] = nd
                heapq.heappush(heap, (nd, u))
    return dist

To recover the path itself, keep a prev dictionary. On every improvement set prev[u] = v. Then walk back from the target.

How does Dijkstra compare with its neighbours?

AlgorithmWeightsTimeUse when
BFSAll equalO(V + E)Step counts, mazes
DijkstraNon-negativeO((V + E) log V)Roads, delays, prices
Bellman-FordAnyO(V · E)Negative edges exist
Floyd-WarshallAnyO(V³)All pairs, small graph

How does it solve Network Delay Time?

You get n nodes, a source, and edges as (from, to, time). Return the time for a signal to reach every node.

Build an adjacency list, run Dijkstra from the source. The answer is the largest distance. If any distance is still infinity, return -1.

What mistakes break a Dijkstra solution?

  • Running it on negative weights. The answer is silently wrong.
  • Not skipping stale pairs. Still correct, just slower.
  • Pushing (node, distance) instead of (distance, node). The heap sorts on the first field.
  • Marking a node settled on push instead of on pop.

How do you explain Dijkstra's algorithm in an interview?

Say: weighted graph, non-negative weights, single source. Name the heap and the greedy pick of the closest node. Give O((V + E) log V).

Then justify the greed. Weights are non-negative. No detour can reach the closest node more cheaply. That is the follow-up question almost every time.

Drill the pattern against its neighbours on the Dijkstra's algorithm page. The unweighted case is on the graph BFS / DFS page.

FAQ

Why does Dijkstra fail with negative weights?

A settled node is treated as final. A negative edge could later shorten the path to it. The algorithm never looks again.

Where does Dijkstra show up in real systems?

Map navigation: junctions are nodes, roads are edges, weights are travel times. Network routing protocols such as OSPF run it on every router. Any planner where an action has a cost.

Do I need a visited set?

No. The check d > dist[v] does the same job. A set is fine for clarity, the result is identical.

How do you run it on a grid with cell costs?

Each cell is a node, its four neighbours are edges. The weight is the cost of the cell you enter. Same code.