š Graph Representation
Think of a social network - Facebook friends, Twitter followers, LinkedIn connections. How do we store these relationships in code? Graphs are everywhere, but choosing the right representation makes all the difference!
The Graph Problem
Graphs model relationships between entities. Before we can work with graphs, we need to represent them in code:
Real-World Graphs
- Social Networks: People (nodes) connected by friendships (edges)
- Maps: Cities (nodes) connected by roads (edges)
- Web: Pages (nodes) connected by links (edges)
- Dependencies: Tasks (nodes) with prerequisites (edges)
- Networks: Computers (nodes) connected by cables (edges)
We need a data structure that can:
- Store vertices (nodes)
- Store edges (connections)
- Efficiently check if an edge exists
- Get all neighbors of a vertex
Three Ways to Represent Graphs
The Three Representations
- Adjacency Matrix: VĆV matrix, matrix[i][j] = 1 if edge exists
- Adjacency List: Each vertex has list of neighbors
- Edge List: Simple list of all edges
Each has different trade-offs!
See the Representations
1. Adjacency Matrix
How It Works
Use a VĆV matrix where:
- matrix[i][j] = 1 if edge from i to j exists
- matrix[i][j] = 0 if no edge
- For weighted graphs, store weight instead of 1
Adjacency Matrix Properties
- Space: O(V²) - Always V² regardless of edges
- Check edge: O(1) - Just matrix[i][j]
- Get neighbors: O(V) - Scan entire row
- Add edge: O(1) - Just set matrix[i][j]
Best for: Dense graphs (E ā V²), when you need fast edge lookups
Worst for: Sparse graphs (wasteful space)
2. Adjacency List
How It Works
Each vertex stores a list of its neighbors:
- adj_list[i] = list of (neighbor, weight) tuples
- Only stores edges that exist
- Space-efficient for sparse graphs
Adjacency List Properties
- Space: O(V + E) - Only stores existing edges
- Check edge: O(degree) - Search in neighbor list
- Get neighbors: O(degree) - Directly available
- Add edge: O(1) - Append to list
Best for: Sparse graphs, most graph algorithms (BFS, DFS, etc.)
Worst for: Frequent edge existence checks
3. Edge List
How It Works
Simple list of all edges:
- edges = [(from, to, weight), ...]
- Minimal representation
- Just stores what's needed
Edge List Properties
- Space: O(E) - Only edges, no vertices
- Check edge: O(E) - Must iterate all edges
- Get neighbors: O(E) - Must search all edges
- Add edge: O(1) - Append to list
Best for: Kruskal's algorithm, when you need to iterate all edges
Worst for: Any operation that needs quick lookups
The Complete Code
Click Run to execute your code
When to Use Each Representation
Decision Guide
| Representation | Use When | Avoid When |
|---|---|---|
| Adjacency Matrix | Dense graph (E ā V²) Need fast edge checks Small graph |
Sparse graph Large graph (memory) |
| Adjacency List | Sparse graph (E << V²) Most algorithms (BFS, DFS) Default choice |
Frequent edge existence checks Very dense graphs |
| Edge List | Kruskal's algorithm Need to iterate all edges Minimal space |
Need neighbor lookups Need edge checks |
Directed vs Undirected Graphs
Representation Differences
Undirected Graph:
- Edge (u, v) means connection both ways
- Adjacency Matrix: matrix[u][v] = matrix[v][u] = 1
- Adjacency List: Add v to u's list AND u to v's list
Directed Graph:
- Edge (u, v) means only u ā v
- Adjacency Matrix: Only matrix[u][v] = 1
- Adjacency List: Only add v to u's list
Weighted Graphs
Storing Weights
- Adjacency Matrix: Store weight at matrix[i][j] instead of 1
- Adjacency List: Store (neighbor, weight) tuples
- Edge List: Store (from, to, weight) tuples
Example: City distances, network latencies, social network strengths
Summary
What You've Learned
Three ways to represent graphs, each with different trade-offs:
- Adjacency Matrix: O(V²) space, O(1) edge check - Best for dense graphs
- Adjacency List: O(V + E) space, O(degree) operations - Best for most cases
- Edge List: O(E) space, O(E) lookups - Best for iterating edges
- Default choice: Adjacency list (best balance)
- Key insight: Choose based on graph density and operations needed
What's Next?
You've learned how to represent graphs! Next, we'll explore BFS (Breadth-First Search) - a fundamental algorithm for traversing graphs level by level, perfect for finding shortest paths in unweighted graphs!
Enjoying these tutorials?