Graph representations: lists vs matrices
◈ 6 cardsAdjacency list vs adjacency matrix — space, edge-test cost, and how we model graphs in Python.
Two ways to store a graph
A graph has a vertex set and an edge set . Throughout graph analysis we abuse notation and write for and for inside asymptotic bounds. There are two standard representations, and choosing the right one is a recurring exam justification.
Adjacency list. An array (or dict) Adj of lists. Adj[u] holds every vertex with .
- Space: — one slot per vertex plus one list entry per edge.
- Edge test ? — you must scan 's list.
- Best for sparse graphs (), which is almost every real graph.
Adjacency matrix. A matrix with iff .
- Space: regardless of edge count.
- Edge test: — one array lookup.
- Best for dense graphs ( near ) or when you need constant-time edge queries.
Why CLRS defaults to lists
Most graphs are sparse, and BFS, DFS, topological sort, and SCC all run in only with adjacency lists — the list lets each algorithm touch every vertex and every edge exactly once (aggregate analysis). On an adjacency matrix, "scan all neighbours of " costs per vertex, dragging those same algorithms up to even on a sparse graph.
Worked example — the scale argument. A social network with users and friendships needs list space but matrix space — the matrix is physically impossible. For a complete graph the two converge: , so a list costs too, and the matrix's edge test wins.
How we model graphs in Python
We use a dict of lists: {u: [v1, v2, ...]}. A directed edge appends v to adj[u] only; an undirected edge appends both directions. The transpose reverses every edge — needed later for strongly connected components.