DSA Notes
Compare adjacency matrix, adjacency list, and edge list representations with code implementations and space-time tradeoff analysis.
The Representation Problem
Before running any graph algorithm, you need to store the graph in memory. The choice of representation dramatically affects both performance and code simplicity. There are three main approaches, and choosing wrong can turn an O(V+E) algorithm into O(V²).
Adjacency Matrix
An adjacency matrix is a 2D array of size V×V where matrix[i][j] = 1 if there is an edge from vertex i to vertex j, and 0 otherwise. For weighted graphs, store the weight instead of 1.
Python Implementation
C++ Implementation
When to Use Adjacency Matrix
- Dense graphs where |E| ≈ V²
- Need O(1) edge existence check
- Small graphs (V < 1000 typically)
- Floyd-Warshall algorithm (needs all-pairs access)
Adjacency List
An adjacency list stores, for each vertex, a list of its neighbors. This is the most common representation and works well for sparse graphs.
| Graph | Adjacency List: |
| 0 --- 1 0 | [1, 2] |
| | | 1 | [0, 3] |
| 2 --- 3 2 | [0, 3] |
| 3 | [1, 2] |
Python Implementation
C++ Implementation
When to Use Adjacency List
- Sparse graphs (most real-world graphs)
- BFS/DFS traversals
- Need to iterate over neighbors efficiently
- Memory is a concern
Edge List
An edge list simply stores all edges as a list of (u, v, weight) tuples. It is the simplest representation but the least efficient for most operations.
class GraphEdgeList:
def __init__(self):
self.edges = []
self.vertices = set()
def add_edge(self, u, v, weight=1):
self.edges.append((u, v, weight))
self.vertices.add(u)
self.vertices.add(v)
def get_neighbors(self, u):
# O(E) - inefficient!
neighbors = []
for a, b, w in self.edges:
if a == u: neighbors.append((b, w))
elif b == u: neighbors.append((a, w))
return neighborsWhen to Use Edge List
- Kruskal's algorithm (sort edges by weight)
- Bellman-Ford (iterate over all edges)
- When you just need to store/transmit the graph
- Very simple problems with few operations
Comparison Table
| Operation | Adj. Matrix | Adj. List | Edge List |
|---|---|---|---|
| Space | O(V²) | O(V + E) | O(E) |
| Add Edge | O(1) | O(1) | O(1) |
| Remove Edge | O(1) | O(degree) | O(E) |
| Check Edge | O(1) | O(degree) | O(E) |
| All Neighbors | O(V) | O(degree) | O(E) |
| Iterate All Edges | O(V²) | O(V + E) | O(E) |
Practical Advice
For competitive programming and interviews, adjacency list is your default choice. It works efficiently with BFS, DFS, Dijkstra, and most graph algorithms. Switch to adjacency matrix only for dense graphs or when you need O(1) edge lookup. Use edge list only for algorithms that explicitly process edges (Kruskal's, Bellman-Ford).
In Python, defaultdict(list) is the quickest way to set up an adjacency list. In C++, vector<vector<pair<int,int>>> is the standard choice for competitive programming due to cache friendliness.
Space Complexity in Practice
For a graph with 10,000 vertices and 50,000 edges:
- Adjacency Matrix: 10,000 × 10,000 = 100 million entries (~400 MB for int)
- Adjacency List: ~10,000 + 100,000 entries (~1 MB)
- Edge List: 50,000 entries (~600 KB)
The difference is dramatic. Most real-world graphs are sparse, which is why adjacency lists dominate in practice.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Graph Representation Methods.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, graphs, graph, representation
Related Data Structures & Algorithms Topics