Hello! Welcome to your lesson on topological sorting.
In our last session, we mastered a crucial algorithm for detecting cycles in directed graphs using DFS. We saw that a cycle exists if we encounter a node that's currently in our recursion stack. This concept is the perfect foundation for today's topic, because the algorithm we're about to study is defined specifically for graphs that don't have cycles.
Today, you'll learn how to perform a topological sort on a Directed Acyclic Graph (DAG). This is a classic graph algorithm and a very common interview pattern for problems involving dependencies, scheduling, or any kind of required ordering. For example, "which courses must you take before others?" or "in what order should a compiler build project files?".
We will cover the two primary methods for this task: a DFS-based approach that builds on what you already know, and an iterative BFS-based approach known as Kahn's Algorithm.
1. What is a Topological Sort?
A topological sort of a Directed Acyclic Graph (DAG) is a linear ordering of its vertices such that for every directed edge from vertex u to vertex v (u -> v), vertex u comes before vertex v in the ordering.
Think of it as flattening a graph's dependencies into a single valid sequence.
A key property of topological sorting is that the resulting order is not always unique. A graph can have multiple valid topological sorts.

This is only possible on a DAG. Why? As we saw in the last lesson, a cycle like A -> B -> C -> A creates a paradox: A must come before B, B before C, and C before A. No linear ordering can satisfy this, so a topological sort is impossible.
For a deeper dive into the intuition behind topological sorting and its real-world applications, the following article provides an excellent overview.
Topological Sort Interview Questions & Tips
Read this article from interviewing.io for an intuitive framing of topological sort, its applications, and heuristics for identifying such problems during an interview.
Read the sections 'What Is Topological Sort?', 'How to Perform Topological Sort', and 'When to Use Topological Sort in Interviews'. This will give you a strong conceptual and practical grounding before we dive into the implementations.
2. Approach 1: DFS-Based Topological Sort
This method is a clever modification of the standard DFS traversal you are already familiar with. The core idea is based on the finish times of the DFS calls.
Intuition: In a DAG, the last node to "finish" its DFS exploration (meaning all its descendants have been fully explored) must be one of the starting points in the dependency chain. Conversely, a node that finishes its DFS call first must be at the end of a dependency chain.
Therefore, if we track the order in which nodes finish their DFS calls and then reverse that order, we get a valid topological sort. A stack is the perfect data structure for this.
Algorithm:
- Initialize a
visitedset and an emptystack. - Iterate through all vertices of the graph. If a vertex hasn't been visited, call a recursive DFS helper function on it.
- In the DFS function for a node
u:
a. Markuas visited.
b. For each neighborvofu, ifvis not visited, recursively call DFS onv.
c. After exploring all ofu's neighbors (i.e., just before the function forureturns), pushuonto the stack. - After the main loop finishes, the stack contains the vertices in a reverse topological order. Popping elements one by one from the stack gives the final topological sort.
To see this in action, the following video provides a clear, step-by-step walkthrough.
G-21. Topological Sort Algorithm | DFS
This video from 'take U forward' demonstrates the DFS-based approach. It explains the logic of using a stack and walks through an example, showing how the stack is populated as the recursion unwinds.
Watch from 03:51 to 08:24. This covers the full algorithm walkthrough. Pay attention to the moment a node is pushed onto the stack—it's after its recursive calls have completed.
Python Implementation
Here is a Python implementation of the DFS-based topological sort. You can also find this code, along with versions in other languages, in the GeeksForGeeks article "Kahn's Algorithm vs DFS Approach".
def topological_sort_dfs(V, adj):
visited = [False] * V
stack = []
def dfs(node):
visited[node] = True
for neighbor in adj[node]:
if not visited[neighbor]:
dfs(neighbor)
# After visiting all neighbors, push current node to stack
stack.append(node)
# Call the recursive helper function to store Topological Sort
# starting from all vertices one by one
for i in range(V):
if not visited[i]:
dfs(i)
# The stack now contains the reverse topological sort.
# We can pop from it or simply reverse it.
return stack[::-1]
# Example Usage:
# V = 6
# adj = [[], [], [3], [1], [0, 1], [0, 2]]
# sort_order = topological_sort_dfs(V, adj)
# print(sort_order) # Output could be [5, 4, 2, 3, 1, 0]
- Time Complexity: . We visit each vertex and edge once.
- Space Complexity: . For the
visitedarray, the recursion stack depth, and the outputstack.
3. Approach 2: Kahn's Algorithm (BFS-Based)
This is an iterative approach that uses Breadth-First Search (BFS). It has a very intuitive logic based on dependencies.
Intuition: A topological sort can only start with a node that has no incoming dependencies. In graph terms, this is a node with an in-degree of 0. The algorithm processes these nodes, "removes" them and their outgoing edges from the graph, and then finds the next set of nodes that now have an in-degree of 0.
Algorithm:
- Compute In-Degrees: Create an array to store the in-degree of every vertex. Iterate through all edges
(u, v)in the graph and increment the in-degree of eachv. - Initialize Queue: Find all vertices with an in-degree of 0 and add them to a queue.
- Process Queue:
a. Initialize an empty list for the topological order.
b. While the queue is not empty:
i. Dequeue a vertexuand append it to the topological order list.
ii. For each neighborvofu:
- Decrement the in-degree ofv(as the dependency fromuis now satisfied).
- If the in-degree ofvbecomes 0, enqueuev. - The list now contains a valid topological sort.
The video below explains this process beautifully.
G-22. Kahn's Algorithm | Topological Sort Algorithm | BFS
This 'take U forward' video is dedicated to Kahn's algorithm. It clearly explains the concept of in-degree and provides a great visual walkthrough of the queue-based process.
Watch from 03:58 to 10:31. Focus on how the in-degree array is calculated first, and then how the queue is populated and processed. See how removing a node effectively unlocks its neighbors.
Python Implementation
Here is a Python implementation of Kahn's Algorithm.
from collections import deque
def topological_sort_kahn(V, adj):
in_degree = [0] * V
for i in range(V):
for neighbor in adj[i]:
in_degree[neighbor] += 1
# Create a queue and enqueue all vertices with in-degree 0
queue = deque([i for i in range(V) if in_degree[i] == 0])
topo_order = []
while queue:
u = queue.popleft()
topo_order.append(u)
# Iterate through all neighboring nodes of dequeued node u
# and decrease their in-degree by 1
for neighbor in adj[u]:
in_degree[neighbor] -= 1
# If in-degree becomes 0, add it to the queue
if in_degree[neighbor] == 0:
queue.append(neighbor)
return topo_order
# Example Usage:
# V = 6
# adj = [[], [], [3], [1], [0, 1], [0, 2]]
# sort_order = topological_sort_kahn(V, adj)
# print(sort_order) # Output could be [4, 5, 0, 2, 3, 1]
- Time Complexity: . to build the in-degree map and for the BFS traversal.
- Space Complexity: . For the
in_degreearray and thequeue.
4. Cycle Detection using Kahn's Algorithm
A neat feature of Kahn's algorithm is its built-in ability to detect cycles.
If the graph has a cycle, the nodes within the cycle (and any nodes that depend on them) will never have their in-degrees reduced to 0. The queue will become empty before all vertices have been processed.
Therefore, a cycle exists if and only if the number of nodes in the final topo_order list is less than the total number of vertices V. This is an important check to include in an interview setting.
Test your understanding!
Consider the graph from the Course Schedule problem in our last lesson: 4 courses with prerequisites [[1,0], [2,1], [3,2], [1,3]]. This represents the edges 0->1, 1->2, 2->3, and 3->1.
- How would the DFS-based sort detect that no valid ordering exists?
- How would Kahn's algorithm detect that no valid ordering exists?
Show answer
-
DFS-based: When performing DFS, you would eventually trace the path
1 -> 2 -> 3. From node3, you'd see an edge back to1. Since1is still in the recursion stack (it's an ancestor in the current path), the cycle detection logic from our previous lesson would trigger, indicating the graph is not a DAG. -
Kahn's Algorithm:
- Initial in-degrees:
in_degree[0]=0,in_degree[1]=2,in_degree[2]=1,in_degree[3]=1. - Only node
0is added to the queue. 0is dequeued.topo_orderis[0]. The in-degree of its neighbor1is decremented to1.- The queue is now empty. No other nodes have an in-degree of 0. The algorithm terminates.
- The final
topo_orderis[0], which has a length of 1. Since1 < 4(the total number of nodes), we conclude that a cycle exists.
- Initial in-degrees:
Conclusion
You have now added two powerful and versatile algorithms to your interview toolkit. Topological sorting is fundamental for any problem involving ordered dependencies.
Key Takeaways:
- Topological Sort creates a linear ordering of vertices in a Directed Acyclic Graph (DAG).
- The DFS-based approach uses a stack to store vertices in the reverse order of their DFS finish times. Its complexity is .
- Kahn's Algorithm (BFS-based) is an iterative approach that uses a queue and the concept of in-degrees. It processes nodes with no incoming dependencies first. Its complexity is also .
- Both methods can be adapted to detect cycles. In Kahn's algorithm, a cycle is present if the final sorted list doesn't contain all vertices.
Preview of the Next Lesson:
We have now extensively covered graph traversal algorithms like DFS and BFS and their applications in cycle detection and topological sorting. Next, we will shift gears to a different but equally important graph-related topic: connectivity. We will learn to implement the Union-Find data structure, a specialized tool designed to efficiently track and merge disjoint sets, which is the key to solving problems like finding the number of connected components in a graph or detecting cycles in an undirected graph with incredible speed.