Chapter 6. Graphs
Classical sequential graph traversals (BFS, DFS) and layering.
This page: Classical forms. View LLP forms »
This page collects the classical / sequential implementations of the algorithms developed in this chapter. The lattice-linear (LLP) reformulations and chapter setup live on the LLP companion page.
Sequential traversals
A graph traversal visits every vertex reachable from a given source. The two standard strategies differ only in the order they explore neighbors:
- Breadth-first search (BFS). Uses a FIFO queue: the source is enqueued first, and at each step the oldest vertex is dequeued and its unvisited neighbors are enqueued. This guarantees that vertices are visited in order of increasing distance (number of edges) from the source. BFS therefore computes shortest (unweighted) distances.
- Depth-first search (DFS). Uses a stack (or recursion): at each step the most recently discovered vertex is explored first, going as deep as possible before backtracking. DFS records discovery and finish times, which classify edges into tree, back, forward, and cross edges — the basis for many later algorithms.
Both run in $O(n + m)$ time on an adjacency-list representation.
Layering a directed acyclic graph
Given a DAG, layering assigns each vertex $v$ to layer $\ell(v) = $ length of the longest path from any source to $v$. Sources (in-degree zero) sit on layer 0. The classical algorithm maintains an in-degree counter for every vertex, enqueues all sources, and peels them off one layer at a time: when a vertex is removed, its successors' in-degrees are decremented, and any that reach zero are enqueued for the next layer. This is essentially a topological sort that additionally tracks the layer number. It runs in $O(n + m)$ time.
Strongly connected components (Kosaraju)
A strongly connected component (SCC) of a directed graph is a maximal set of vertices such that every vertex is reachable from every other. Kosaraju's algorithm finds all SCCs in two passes of DFS:
- Run DFS on the original graph and push each vertex onto a stack in order of decreasing finish time.
- Pop vertices from the stack one at a time. For each unvisited vertex, run DFS on the transpose graph (all edges reversed); the set of vertices visited in that DFS forms one SCC.
Both passes run in $O(n + m)$ time, so the total cost is $O(n + m)$.
Traversal
Generic queue-based reachability from vertex 0; matches the book's "removeAny" sequential traversal. Returns $G[i] = 1$ iff $v_i$ is reachable.
Time complexity: $O(n + m)$, where $n$ is the number of vertices and $m$ is the number of edges.
BFS
FIFO-queue BFS distance computation. Sets $G[i] = $ shortest-edge-count distance from
source $s$, or Integer.MAX_VALUE if unreachable.
Time complexity: $O(n + m)$, where $n$ is the number of vertices and $m$ is the number of edges.
DFS
Recursive DFS recording discovery and finish times. parent[] records the
DFS-tree parent (-1 for the root); a 1-element array t rides on the
recursion to share the global tick counter.
Time complexity: $O(n + m)$, where $n$ is the number of vertices and $m$ is the number of edges.
Layering
The classical in-degree-zero queue version of layering. Computes $G[j] = $ length of the longest path from any source vertex to $j$.
Time complexity: $O(n + m)$, where $n$ is the number of vertices and $m$ is the number of edges.