Hello! In our previous lesson, we established the fundamental theorem that a directed graph possesses a topological ordering if and only if it is a Directed Acyclic Graph (DAG). The proof for one direction of this theorem was particularly constructive: we showed that by repeatedly finding a vertex with an in-degree of 0, adding it to our ordering, and removing it from the graph, we could build a valid topological sort.
Today, we will turn that constructive proof into a concrete algorithm. This lesson focuses on implementing Kahn's algorithm, which is a direct application of that idea. It uses a Breadth-First Search (BFS) approach, combined with tracking vertex in-degrees, to efficiently generate a topological ordering. By the end of this lesson, you will be able to implement this essential algorithm in C++, a crucial tool for many competitive programming problems involving prerequisites or ordered tasks.
1. The Core Idea: An Algorithmic Translation of the Proof
Recall the key property we proved: every non-empty DAG has at least one vertex with an in-degree of 0. These vertices are "sources" with no prerequisites, so they can safely come first in a topological ordering.
Kahn's algorithm systematizes this. Imagine we have a set of all tasks we can currently perform (those with no pending prerequisites). We pick one, "complete" it, and then update the prerequisite status of all tasks that depended on it. As we complete tasks, new ones may become available. This is the essence of the algorithm.
To implement this, we need a few components:
- An adjacency list to represent the graph.
- An array or map to store the current in-degree of each vertex.
- A queue to maintain the set of vertices with an in-degree of 0 that are ready to be processed. This is why the algorithm is considered BFS-based.
- A result list to build the topological order.

2. The Algorithm Step-by-Step
The algorithm proceeds in three main phases: initialization, processing, and finalization.
Phase 1: Initialization
- Compute In-degrees: Iterate through all the edges in the graph. For each edge , increment the in-degree count for vertex . This pass gives us the initial in-degree for every vertex.
- Populate the Queue: Iterate through all the vertices. Any vertex with an initial in-degree of 0 is a source. Add all such vertices to the queue.
This initial state is shown in the image below. The nodes with an in-degree of 0 (4, 5, and 6) are placed in the queue, ready to be processed.

Phase 2: Processing Loop
This is the main loop, which runs as long as the queue is not empty. It's very similar to a standard BFS traversal.
- Dequeue a Vertex: Remove a vertex, let's call it
u, from the front of the queue. - Add to Order: Append
uto your result list. This vertex is now officially placed in the topological ordering. - Update Neighbors: For each neighbor
vofu(i.e., for each edge ):- Decrement the in-degree of
v. Conceptually, this is like removing the edge fromutovbecause the prerequisiteuis now satisfied. - If the in-degree of
vbecomes 0, it means all its prerequisites are met. Addvto the queue.
- Decrement the in-degree of
Phase 3: Finalization & Cycle Detection
- After the loop terminates (i.e., the queue is empty), check if the number of vertices in your result list is equal to the total number of vertices in the graph.
- If it is: You have successfully found a valid topological ordering.
- If it is not: The graph contains a cycle. The loop terminated because the queue became empty, but there were still vertices left in the graph with in-degrees greater than 0. These vertices are part of a cycle and could never have their in-degrees reduced to 0.
The following video provides an excellent, animated walkthrough of this process, clearly showing how the in-degree counts and the queue change over time.
Topological Sort | Kahn's Algorithm | Graph Theory
This video from WilliamFiset's channel provides a clear, step-by-step animation of Kahn's algorithm on a moderately complex graph.
Watch the detailed example from the walkthrough. Pay close attention to how the in_degree array is updated and how nodes are added to the queue only when their in-degree drops to zero.
3. Implementation in C++
Now, let's translate this logic into C++. Given your competitive programming background, the structure should feel familiar. We will use a std::vector<int> in_degree, a std::queue<int>, and std::vector<int> adj[] for the adjacency list.
The following resource provides a concise walkthrough and a clear C++ implementation tailored for competitive programming.
G-22. Kahn's Algorithm | Topological Sort Algorithm | BFS
The channel "take U forward" is a staple in the competitive programming community. This video explains Kahn's algorithm from that perspective.
Watch the introduction to the in-degree concept from In-degree Intuition. Follow the step-by-step example from Algorithm Walkthrough to see the logic in action again. Finally, examine the C++ code implementation and complexity analysis from Code and Complexity.
Here is the core logic in C++, reflecting the structure discussed in the video.
#include <iostream>
#include <vector>
#include <queue>
#include <list>
// V: number of vertices, adj: adjacency list
std::vector<int> topologicalSort(int V, std::vector<int> adj[]) {
// 1. Initialization
std::vector<int> in_degree(V, 0);
for (int i = 0; i < V; i++) {
for (int neighbor : adj[i]) {
in_degree[neighbor]++;
}
}
std::queue<int> q;
for (int i = 0; i < V; i++) {
if (in_degree[i] == 0) {
q.push(i);
}
}
std::vector<int> topo_order;
// 2. Processing Loop
while (!q.empty()) {
int u = q.front();
q.pop();
topo_order.push_back(u);
for (int v : adj[u]) {
in_degree[v]--;
if (in_degree[v] == 0) {
q.push(v);
}
}
}
// 3. Finalization / Cycle Check
if (topo_order.size() == V) {
return topo_order;
} else {
// Graph has a cycle, return an empty list to indicate failure.
return {};
}
}
A Note on Correctness and Complexity
As you prefer to understand the theory, let's briefly touch upon why this works and its efficiency.
Detecting Cycles in a Directed Graph
This resource provides a formal proof of correctness for Kahn's algorithm, which solidifies the connection between the algorithm's behavior and the properties of DAGs.
Read the proof section, which uses induction to show that all vertices in an acyclic graph will be processed. Also, read the complexity analysis that follows.
The key takeaways on correctness and complexity are:
- Correctness:
- If the graph is a DAG, we proved it must have a source. Our algorithm finds it. By removing it, the remaining subgraph is also a DAG, which must also have a source. The algorithm correctly continues this process until all nodes are visited.
- If the graph has a cycle, no node within the cycle can ever have its in-degree become 0 by removing other nodes in the cycle. Therefore, the queue will eventually become empty while these cyclic nodes remain, and
topo_order.size()will be less thanV.
- Time Complexity: , where is the number of vertices and is the number of edges.
- Calculating initial in-degrees takes time as we iterate through each adjacency list once.
- Initializing the queue takes time.
- The main loop processes each vertex and each edge exactly once. Each vertex is enqueued and dequeued once. When a vertex
uis dequeued, we iterate through its outgoing edges. Over the entire algorithm, this means we visit each edge once.
- Space Complexity: to store the
in_degreearray, the queue, and the result.
Conclusion
In this lesson, you've transformed the theoretical foundation from our previous session into a practical and efficient algorithm. Kahn's algorithm is a powerful tool that not only generates a topological sort but also doubles as a cycle detector for directed graphs.
Key Takeaways:
- Kahn's algorithm is a direct implementation of the constructive proof that every DAG has a topological order.
- It operates by iteratively processing nodes with an in-degree of 0, using a queue in a manner similar to BFS.
- The core steps are: calculate all in-degrees, initialize a queue with source nodes, and then process the queue by decrementing neighbors' in-degrees and adding new source nodes as they appear.
- If the final sorted list contains fewer vertices than the graph, a cycle has been detected.
- The algorithm runs in linear time, , making it highly efficient for competitive programming problems.
In our next lesson, we will explore an alternative method for topological sorting that is based on Depth-First Search (DFS). This will provide you with another powerful perspective and a different set of trade-offs for solving problems on DAGs.