DISCRETE MATH • GRAPH THEORY

Represent graphs (adjacency list/matrix)

How adjacency lists and adjacency matrices encode graph structure for analysis and computation.

Historical Context & Motivation

The study of graphs began long before computers existed, but the need to represent graph structure in a concrete data format became urgent only when algorithms had to traverse, search, and manipulate graphs at scale. Leonhard Euler's 1736 solution to the Königsberg bridge problem is widely regarded as the origin of graph theory, yet Euler never needed a machine-readable encoding — his argument was purely existential. As combinatorics matured through the 19th century and electronic computation emerged in the 20th, researchers required efficient, unambiguous ways to store vertices and edges in memory. The two dominant representations that crystallised — the adjacency matrix and the adjacency list — reflect a fundamental trade-off between random-access speed and memory economy that pervades all of computer science.

1736
Euler and Königsberg
Leonhard Euler solves the Seven Bridges of Königsberg problem, founding graph theory. Graphs are treated as abstract objects without any formal data representation.
1946
Matrix Representation Formalized
As linear algebra gained prominence in combinatorics, researchers including André Sainte-Laguë formally defined the adjacency matrix, enabling algebraic graph theory and spectral analysis.
1956
Dijkstra and Shortest Paths
Edsger Dijkstra develops his shortest-path algorithm, motivating the use of adjacency lists to efficiently enumerate neighbours during graph traversal on early computers.
1970s
Algorithmic Graph Theory Matures
Texts by Tarjan, Hopcroft, and others codify the adjacency list as the preferred representation for sparse-graph algorithms such as DFS, BFS, and strongly connected components.
2000s+
Modern Large-Scale Graphs
Social networks and web graphs with billions of edges make representation choice critical. Compressed sparse row (CSR) formats and distributed adjacency structures extend the classical ideas.

The central question this lesson addresses is: given a graph G = (V, E), how do we store it so that common operations — checking edge existence, iterating over neighbours, and computing graph properties — can be performed correctly and efficiently? The answer depends on the graph's density and the operations you need, which is why both the adjacency matrix and adjacency list remain essential tools in a discrete mathematician's repertoire.

Core Principles & Definitions

Before discussing specific representations, we must establish precise terminology. A graph G = (V, E) consists of a finite set V of vertices (also called nodes) and a set E of edges connecting pairs of vertices. When edges have no direction, the graph is undirected; when each edge is an ordered pair, it is directed (a digraph). Both types arise constantly in applications — social networks model undirected friendships, while web-page links form directed graphs. A representation must faithfully capture these distinctions.

1

Adjacency Matrix

A |V| × |V| matrix A where entry A[i][j] = 1 if edge (i, j) ∈ E, and 0 otherwise. For undirected graphs, A is symmetric. Space: Θ(|V|²).
2

Adjacency List

An array of |V| lists, where Adj[v] contains all vertices u such that (v, u) ∈ E. Space: Θ(|V| + |E|), making it ideal for sparse graphs.
3

Dense vs. Sparse

A graph is dense when |E| ≈ |V|², and sparse when |E| ≪ |V|². This distinction is the primary factor when choosing between a matrix and a list representation.
4

Weighted Edges

In a weighted graph, each edge carries a numerical weight. The adjacency matrix stores weights in place of 1s; the adjacency list stores (neighbour, weight) pairs.
5

Self-Loops & Multi-Edges

A self-loop is an edge from a vertex to itself (A[i][i] ≠ 0). Multi-graphs allow multiple edges between the same pair; adjacency matrices can store counts, while lists simply include duplicates.
KEY TAKEAWAY
Think of an adjacency matrix as a spreadsheet grid: every possible connection has its own cell, so looking up any specific connection is instantaneous, but you pay for every empty cell. An adjacency list is more like a phone contact list for each person — you only record the people they actually know, so you waste no space on strangers, but checking whether two specific people are connected means scanning a list. In engineering terms, the matrix trades memory for O(1) edge queries, while the list trades query speed for O(|V| + |E|) compactness.

Visual Explanation — From Graph to Representation

The following diagram illustrates a small undirected graph with five vertices and six edges alongside its two representations. On the left, the graph is drawn in the standard node-and-edge style. In the centre, the same graph is encoded as an adjacency matrix, and on the right, as an adjacency list. Study how the edge between vertices 1 and 3, for example, appears as A[1][3] = A[3][1] = 1 in the matrix and as '3' in the list of vertex 1 (and '1' in the list of vertex 3).

A five-vertex undirected graph (left) with its adjacency matrix (centre) and adjacency list (right). Notice the matrix is symmetric along the main diagonal, reflecting the undirected nature of the edges.

Several structural properties are immediately visible. In the adjacency matrix, the main diagonal is all zeros because the graph contains no self-loops. The matrix is symmetric — entry A[0][1] = 1 mirrors A[1][0] = 1 — a hallmark of undirected graphs. In the adjacency list, each vertex's list has length equal to its degree: vertex 1 has degree 3 because it connects to vertices 0, 2, and 3. Observe also that the total number of entries across all lists equals 2|E| = 12, since every undirected edge appears twice — once from each endpoint.

Mathematical Framework

The adjacency matrix is not merely a storage format — it is a rich algebraic object. Spectral graph theory exploits the eigenvalues of the adjacency matrix to derive structural properties of the graph, while powers of the matrix count walks of given lengths. Below we formalise both representations and state the key algebraic results.

ADJACENCY MATRIX DEFINITION
A[i][j] = { 1 if {vᵢ, vⱼ} ∈ E, 0 otherwise }
For a weighted graph, replace 1 with the edge weight w(vᵢ, vⱼ), and for directed graphs, A need not be symmetric: A[i][j] = 1 means an arc from vᵢ to vⱼ.
SPACE COMPLEXITY — ADJACENCY MATRIX
Space(A) = Θ(|V|²)
Regardless of edge count, the matrix allocates one entry per vertex pair. Edge lookup is O(1), but iterating over all neighbours of a vertex is Θ(|V|).
SPACE COMPLEXITY — ADJACENCY LIST
Space(Adj) = Θ(|V| + |E|)
The array has |V| entries, and the total length of all lists equals 2|E| (undirected) or |E| (directed). Iterating over all neighbours of vertex v costs O(deg(v)), but checking a specific edge (u, v) costs O(deg(u)) in the worst case.
WALK-COUNTING THEOREM
(Aᵏ)[i][j] = number of walks of length k from vᵢ to vⱼ
This fundamental result shows that raising the adjacency matrix to the k-th power counts all walks (not necessarily paths) of exactly k steps. In particular, trace(A²) equals twice the number of edges, and trace(A³) / 6 counts the number of triangles in an undirected graph.

For the degree of vertex vᵢ in an undirected graph, the adjacency matrix provides a clean formula: deg(vᵢ) = Σⱼ A[i][j], the row sum. For directed graphs, the row sum gives the out-degree and the column sum gives the in-degree. Meanwhile, the Handshaking Lemma — Σᵥ deg(v) = 2|E| — can be verified immediately from the matrix representation since the total of all entries is exactly 2|E|.

Directed Graph Representations

Directed graphs (digraphs) introduce an asymmetry that both representations must capture. In the adjacency matrix, A[i][j] = 1 indicates an arc from vertex i to vertex j, but A[j][i] may equal 0 if there is no arc in the reverse direction. The matrix is therefore not necessarily symmetric. In an adjacency list, the list Adj[u] contains v if and only if the arc (u, v) exists; a separate 'reverse' adjacency list can be maintained if incoming-neighbour queries are frequent. The following diagram shows a directed graph on four vertices with five arcs.

A directed graph on four vertices. The adjacency matrix is no longer symmetric — A[A][B] = 1 but A[B][A] = 0 because there is an arc from A to B but not from B to A. The adjacency list stores only outgoing neighbours.
🔄 Transpose and Reverse Graphs
The transpose of a digraph G is obtained by reversing every arc. In matrix terms, the adjacency matrix of Gᵀ is simply Aᵀ — the matrix transpose. This operation is trivially O(|V|²) with a matrix, but with adjacency lists, building the reverse graph requires scanning all lists and reconstructing, taking Θ(|V| + |E|). Kosaraju's algorithm for strongly connected components exploits this transpose.

Worked Example — Building Both Representations

Consider an undirected, weighted graph G with vertices {0, 1, 2, 3} and edges {(0,1, w=4), (0,2, w=3), (1,2, w=1), (1,3, w=7), (2,3, w=5)}. We will construct both the adjacency matrix and the adjacency list, then answer two queries.

Construct Representations and Answer Queries
1
Step 1 — Initialize the adjacency matrixCreate a 4 × 4 matrix A initialised to 0 (or ∞ for weighted shortest-path contexts). The rows and columns are indexed by the vertex labels 0, 1, 2, 3.
A = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
2
Step 2 — Fill in edge weights symmetricallyFor each edge (u, v, w), set A[u][v] = A[v][u] = w. Edge (0,1,4): A[0][1] = A[1][0] = 4. Edge (0,2,3): A[0][2] = A[2][0] = 3. Edge (1,2,1): A[1][2] = A[2][1] = 1. Edge (1,3,7): A[1][3] = A[3][1] = 7. Edge (2,3,5): A[2][3] = A[3][2] = 5.
A = [[0,4,3,0],[4,0,1,7],[3,1,0,5],[0,7,5,0]]
3
Step 3 — Build the adjacency listCreate an array of 4 empty lists. For each edge (u, v, w), append (v, w) to Adj[u] and (u, w) to Adj[v].
Adj[0] = [(1,4),(2,3)] Adj[1] = [(0,4),(2,1),(3,7)] Adj[2] = [(0,3),(1,1),(3,5)] Adj[3] = [(1,7),(2,5)]
4
Step 4 — Query: Is there an edge between 0 and 3?Using the matrix: check A[0][3]. The value is 0, indicating no edge. Using the list: scan Adj[0] = [(1,4),(2,3)] — vertex 3 does not appear, so no edge exists. The matrix query is O(1); the list query is O(deg(0)) = O(2).
No edge between 0 and 3
5
Step 5 — Query: What is the degree of vertex 2?Using the matrix: sum row 2 (counting nonzero entries): A[2][0]=3, A[2][1]=1, A[2][3]=5 → three nonzero entries, so deg(2) = 3. Using the list: |Adj[2]| = 3. Both confirm degree 3.
deg(2) = 3

Strengths & Limitations — Choosing a Representation

Neither representation dominates the other in all scenarios. The correct choice depends on the graph's density and the operations your algorithm performs most frequently. The following table summarises the key trade-offs.

Complexity comparison of adjacency matrix vs. adjacency list
OperationAdjacency MatrixAdjacency List
SpaceΘ(|V|²)Θ(|V| + |E|)
Check edge (u, v)O(1)O(deg(u))
List all neighbours of vΘ(|V|)O(deg(v))
Add an edgeO(1)O(1) amortised
Remove an edgeO(1)O(deg(u))
Iterate all edgesΘ(|V|²)Θ(|V| + |E|)
Best forDense graphs, matrix algebraSparse graphs, traversals
⚖️ WHEN TO USE WHICH
A useful heuristic: if your graph has n vertices and significantly fewer than n² / 2 edges, prefer the adjacency list. Most real-world graphs — social networks, road networks, the internet — are sparse, which is why adjacency lists (or their compressed cousins like CSR format) dominate in practice. Adjacency matrices excel when the graph is dense (e.g., a tournament) or when you need matrix operations like computing powers of A to count walks, or eigenvalue analysis for spectral clustering.

Connection to Advanced Theory

The basic adjacency matrix and adjacency list serve as the foundation upon which more sophisticated representations are built. In large-scale computing, compressed formats become essential, and in theoretical computer science, representation choices underpin the analysis of algorithm complexity classes for graph problems.

From basic to advanced graph representations
Basic RepresentationAdvanced ExtensionUse Case / Benefit
Adjacency MatrixLaplacian Matrix L = D − ASpectral clustering, counting spanning trees (Kirchhoff's theorem), graph connectivity
Adjacency MatrixIncidence MatrixNetwork flow formulations, cycle space analysis
Adjacency ListCompressed Sparse Row (CSR)Cache-friendly traversal in billion-edge graphs, GPU graph algorithms
Adjacency ListEdge ListKruskal's MST, streaming/external-memory algorithms
BothImplicit / Procedural GraphsState-space search (AI), where edges are generated on-the-fly by successor functions

Looking ahead, courses in algorithms will consistently ask you to analyse the complexity of graph routines in terms of |V| and |E|. The representation you choose determines whether BFS runs in O(|V| + |E|) (with an adjacency list) or O(|V|²) (with a matrix). For problems like all-pairs shortest paths (Floyd–Warshall), the Θ(|V|³) algorithm naturally pairs with a matrix. Understanding both representations — and knowing how to convert between them — is therefore prerequisite knowledge for virtually all of algorithmic graph theory.

Practice Problems

PROBLEM 1CONCEPTUAL
Explain why the adjacency matrix of an undirected graph is always symmetric. What property does the matrix gain (or lose) when the graph becomes directed?
PROBLEM 2BASIC CALCULATION
Given the adjacency matrix below for an undirected graph on vertices {A, B, C, D}, write out the adjacency list representation. A = [[0,1,0,1],[1,0,1,1],[0,1,0,0],[1,1,0,0]]
PROBLEM 3INTERMEDIATE
A directed graph G on 5 vertices has the adjacency list: Adj[0] = [1, 2], Adj[1] = [3], Adj[2] = [1, 4], Adj[3] = [4], Adj[4] = [0]. (a) Write the 5 × 5 adjacency matrix. (b) Compute A² and determine the number of walks of length 2 from vertex 0 to vertex 4.
PROBLEM 4APPLIED
A city has 1,000 intersections and 3,500 road segments (each road is bidirectional). You are designing a GPS navigation system that frequently needs to find shortest paths. (a) How much memory (in entries) would an adjacency matrix require versus an adjacency list? (b) Which representation would you choose for Dijkstra's algorithm, and why?
PROBLEM 5CRITICAL THINKING
Prove that the trace of A² (where A is the adjacency matrix of a simple undirected graph) equals twice the number of edges. Then explain why trace(A³) / 6 counts the number of triangles.

Lesson Summary

Graph representations translate the abstract idea of vertices and edges into concrete data structures. The adjacency matrix is a |V| × |V| array providing O(1) edge lookups at the cost of Θ(|V|²) space, making it ideal for dense graphs and algebraic operations such as computing matrix powers to count walks. It is symmetric for undirected graphs and extends naturally to weighted or directed graphs.

The adjacency list stores only the actual edges, consuming Θ(|V| + |E|) space and enabling efficient neighbour iteration in O(deg(v)), which is why it dominates in sparse-graph algorithms like BFS, DFS, and Dijkstra's shortest path. Choosing the right representation is not merely a matter of taste — it fundamentally determines the time and space complexity of every graph algorithm you implement.

Varsity Tutors • Discrete Math • Represent graphs (adjacency list/matrix)