Lecture 20
What Is a Graph?
A graph is a set of vertices (also called nodes) connected by edges. Unlike a tree, a graph has no root, no parent-child hierarchy, and may contain cycles — paths that loop back to a vertex already visited.
Two fundamental distinctions:
- Undirected — edges have no direction; an edge between A and B means you can travel in either direction. Directed (digraph) — each edge has a specific direction, written A → B.
- Unweighted — edges carry no cost. Weighted — each edge carries a numeric weight (distance, latency, cost).
Lecture 21 will use directed graphs for topological sort. Here we focus on undirected, unweighted graphs and the two fundamental traversal algorithms: BFS and DFS.
Representing a Graph
Two standard representations exist:
| Representation | Storage | Add edge | Check edge | Best when |
|---|---|---|---|---|
| Adjacency list | O(V + E) | O(1) | O(degree) | sparse graphs (few edges) |
| Adjacency matrix | O(V²) | O(1) | O(1) | dense graphs (many edges) |
An adjacency list stores, for each vertex, the list of vertices it connects to. An adjacency matrix stores a V×V grid where matrix[u][v] == 1 means an edge exists between u and v.
Most graph algorithms use an adjacency list: traversing all neighbors of vertex u takes O(degree(u)) instead of O(V).
Graph Class
Each vertex is an integer in [0, vertices). add_edge appends to both neighbor lists because the graph is undirected.
Breadth-First Search
BFS visits vertices layer by layer starting from a source vertex. It is the graph equivalent of level-order traversal on a tree: all vertices at distance 1 are visited before any vertex at distance 2.
The algorithm uses a queue and a visited array to prevent revisiting vertices — trees never revisit, but graphs can have cycles:
- Mark the source visited and enqueue it.
- While the queue is non-empty: dequeue a vertex, print it, enqueue all unvisited neighbors and mark them visited.
BFS on the example graph starting at 0:
Marking a vertex visited when it is enqueued (not when it is dequeued) is critical. If you wait until dequeue, the same vertex can be enqueued multiple times through different neighbors, producing duplicate visits.
Depth-First Search
DFS visits as deep as possible before backtracking — the graph equivalent of preorder traversal on a tree. It uses recursion (the implicit call stack) and the same visited array to avoid cycles.
DFS on the same graph starting at 0:
Without the visited array, DFS on a cycle never terminates. A tree has no cycles so tree
traversals never revisit a node — graph DFS always needs this guard.
BFS vs DFS
| Property | BFS | DFS |
|---|---|---|
| Data structure | Queue | Call stack (recursion) |
| Order | Layer by layer | Deep first, then backtrack |
| Shortest path (unweighted) | Yes — first visit is shortest | No — may not find shortest path |
| Memory | O(V) queue at peak | O(V) call stack at peak |
| Typical uses | Shortest path, connected components | Cycle detection, topological sort |
Exercises
Q1.
Without running the code, predict what this program prints.
Q2.
Without running the code, predict what this program prints.
Q3.
Each snippet has a bug related to graph traversal. Identify what's wrong.
Q4.
Implement bfs for the graph below.
Q5.
Implement dfs and dfs_helper for the graph below.
Practice Problems
- Flood Fill — Easy
- Number of Islands — Medium
- Clone Graph — Medium
- Course Schedule — Medium