Learn how to model networks, vertices, and edges using Adjacency Lists and Adjacency Matrices with complexity tradeoffs.
Learn how dynamic arrays achieve O(1) amortized insertion, contiguous memory layout, and geometric doubling strategies.
A Graph $G = (V, E)$ consists of a set of vertices ($V$) connected by edges ($E$). Graphs can be directed (one-way streets) or undirected (two-way friendships), and weighted or unweighted.
Graph: (0) ───── (1)
│ /
│ /
(2) ── (3)
Adjacency List (Map / Array of Lists):
0: [ 1, 2 ]
1: [ 0, 3 ]
2: [ 0, 3 ]
3: [ 1, 2 ]
Adjacency Matrix (2D Grid):
0 1 2 3
0 [ 0, 1, 1, 0 ]
1 [ 1, 0, 0, 1 ]
2 [ 1, 0, 0, 1 ]
3 [ 0, 1, 1, 0 ]
function buildGraph(numVertices, edges) {
const adjList = new Map();
for (let i = 0; i < numVertices; i++) {
adjList.set(i, []);
}
for (const [u, v] of edges) {
adjList.get(u).push(v);
adjList.get(v).push(u); // Add reverse edge for undirected graph!
}
return adjList;
}
const graph = buildGraph(4, [[0, 1], [0, 2], [1, 3], [2, 3]]);
console.log(graph.get(0)); // Output: [1, 2]
| Feature | Adjacency List | Adjacency Matrix |
|---|---|---|
| Space Complexity | $O(V + E)$ (Optimal for sparse graphs) | $O(V^2)$ (Heavy memory) |
| Check Edge $(u, v)$ | $O( ext(u))$ | $O(1)$ (matrix[u][v] === 1) |
| Iterate Neighbors | $O( ext(u))$ | $O(V)$ (Scan entire row) |
Use adjacency lists for network representations. Next, let's explore Graph Traversals: BFS & DFS!