Graphs#
Python has no stdlib graph type; represent a graph as a
dict[node, list[node]] (adjacency list) or
dict[node, dict[node, weight]] for weighted graphs.
Representation#
graph = {
"a": ["b", "c"],
"b": ["d"],
"c": ["d", "e"],
"d": ["e"],
"e": [],
}
BFS (shortest-hop)#
from collections import deque
def bfs(graph, start, goal):
q = deque([(start, [start])])
seen = {start}
while q:
node, path = q.popleft()
if node == goal:
return path
for n in graph[node]:
if n not in seen:
seen.add(n)
q.append((n, path + [n]))
return None
DFS (recursive)#
def dfs(graph, start, goal, seen=None):
seen = seen or set()
seen.add(start)
if start == goal:
return [start]
for n in graph[start]:
if n not in seen:
sub = dfs(graph, n, goal, seen)
if sub:
return [start] + sub
return None
Dijkstra (shortest path, non-negative weights)#
import heapq
def dijkstra(graph, start):
"""graph: {node: {neighbor: weight}}. Returns {node: distance}."""
dist = {start: 0}
pq = [(0, start)]
while pq:
d, node = heapq.heappop(pq)
if d > dist.get(node, float("inf")):
continue
for nb, w in graph[node].items():
nd = d + w
if nd < dist.get(nb, float("inf")):
dist[nb] = nd
heapq.heappush(pq, (nd, nb))
return dist
Topological sort#
Use graphlib.TopologicalSorter (stdlib, 3.9+).
from graphlib import TopologicalSorter
ts = TopologicalSorter({
"build": {"compile"},
"test": {"build"},
"ship": {"test"},
"compile": set(),
})
list(ts.static_order()) # ['compile', 'build', 'test', 'ship']
TopologicalSorter.prepare() raises CycleError if the
graph has a cycle.
References#
deque for the BFS queue.
Heap for the Dijkstra priority queue.
graphlib — Functionality to operate with graph-like structures.