Dijkstra in Python with heapq
Dijkstra finds the shortest path in a weighted graph with non-negative edge weights. The Python idiom is `heapq` (a binary min-heap) plus a distance dict, which gives O((V + E) log V) without external libraries. This entry covers the standard single-source template, path reconstruction, and the early-exit shortest-path-to-one-target variant.
674 views
16
import heapq
from collections import defaultdict
def dijkstra(graph, source):
"""Shortest distance from source to every reachable node.
graph: dict-of-lists where graph[u] = [(v, weight), ...]
"""
dist = {source: 0}
heap = [(0, source)] # (distance, node)
while heap:
d, u = heapq.heappop(heap)
if d > dist[u]:
continue # stale entry left over from a tighter relaxation
for v, w in graph[u]:
nd = d + w
if nd < dist.get(v, float('inf')):
dist[v] = nd
heapq.heappush(heap, (nd, v))
return dist
# Build a small weighted graph.
graph = defaultdict(list)
for u, v, w in [('A', 'B', 4), ('A', 'C', 1), ('C', 'B', 2),
('B', 'D', 1), ('C', 'D', 5), ('D', 'E', 3)]:
graph[u].append((v, w))
graph[v].append((u, w)) # undirected
print(dijkstra(graph, 'A'))
# {'A': 0, 'C': 1, 'B': 3, 'D': 4, 'E': 7}
# Disconnected: 'X' has no edges, only itself reachable.
lonely = defaultdict(list)
lonely['X'] = []
print(dijkstra(lonely, 'X')) # {'X': 0}The heap stores (tentative_distance, node) tuples and heappop always returns the smallest. Because Python's heapq does not support decrease-key, the standard trick is to push a fresh entry every time you find a shorter path and to discard stale pops with the if d > dist[u]: continue guard. This adds at most one stale entry per relaxation, so the heap stays O(E) in size and the total runtime is O((V + E) log V). The algorithm only works for non-negative weights; a single negative edge can produce paths that need to be revisited, which Dijkstra cannot do.
2 more snippets in this entry are available for premium members.
Upgrade to Premium