Python Program to Find Topological Sort
def topological_sort(graph): visited=set(); stack=[]; def dfs(node): visited.add(node); for n in graph[node]: if n not in visited: dfs(n); stack.append(node); for node in graph: if node not in visited: dfs(node); return stack[::-1].Examples
How to Think About It
Algorithm
Code
def topological_sort(graph): visited = set() stack = [] def dfs(node): visited.add(node) for neighbor in graph.get(node, []): if neighbor not in visited: dfs(neighbor) stack.append(node) for node in graph: if node not in visited: dfs(node) return stack[::-1] # Example usage graph = {'A': ['C'], 'B': ['C', 'D'], 'C': ['E'], 'D': ['F'], 'E': ['H', 'F'], 'F': ['G'], 'G': [], 'H': []} print(topological_sort(graph))
Dry Run
Let's trace the example graph through the code
Start DFS from node 'A'
visited = {'A'}; call dfs on 'C'
Visit 'C' neighbors
visited = {'A', 'C'}; call dfs on 'E'
Visit 'E' neighbors
visited = {'A', 'C', 'E'}; call dfs on 'H' and 'F'
Visit 'H' (no neighbors)
visited = {'A', 'C', 'E', 'H'}; add 'H' to stack
Visit 'F' neighbors
visited = {'A', 'C', 'E', 'H', 'F'}; call dfs on 'G'
Visit 'G' (no neighbors)
visited = {'A', 'C', 'E', 'H', 'F', 'G'}; add 'G' to stack
Add 'F' and 'E' to stack after neighbors
stack = ['H', 'G', 'F', 'E']
Add 'C' and 'A' to stack
stack = ['H', 'G', 'F', 'E', 'C', 'A']
Start DFS from node 'B'
visited = {'A', 'B', 'C', 'E', 'F', 'G', 'H'}; call dfs on 'C' and 'D'
Visit 'D' neighbors
visited = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'}; call dfs on 'F' (already visited)
Add 'D' and 'B' to stack
stack = ['H', 'G', 'F', 'E', 'C', 'A', 'D', 'B']
Reverse stack for result
result = ['B', 'D', 'A', 'C', 'E', 'H', 'F', 'G']
| Step | Visited Set | Stack |
|---|---|---|
| 1 | {'A'} | [] |
| 2 | {'A', 'C'} | [] |
| 3 | {'A', 'C', 'E'} | [] |
| 4 | {'A', 'C', 'E', 'H'} | ['H'] |
| 5 | {'A', 'C', 'E', 'H', 'F'} | ['H'] |
| 6 | {'A', 'C', 'E', 'H', 'F', 'G'} | ['H', 'G'] |
| 7 | {'A', 'C', 'E', 'H', 'F', 'G'} | ['H', 'G', 'F', 'E'] |
| 8 | {'A', 'C', 'E', 'H', 'F', 'G'} | ['H', 'G', 'F', 'E', 'C', 'A'] |
| 9 | {'A', 'B', 'C', 'E', 'F', 'G', 'H'} | ['H', 'G', 'F', 'E', 'C', 'A'] |
| 10 | {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'} | ['H', 'G', 'F', 'E', 'C', 'A'] |
| 11 | {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'} | ['H', 'G', 'F', 'E', 'C', 'A', 'D', 'B'] |
| 12 | {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'} | ['B', 'D', 'A', 'C', 'E', 'H', 'F', 'G'] |
Why This Works
Step 1: Visit nodes only once
Using a visited set ensures each node is processed once, avoiding infinite loops.
Step 2: Post-order addition
Nodes are added to the stack after all their neighbors are visited, ensuring dependencies come first.
Step 3: Reverse stack for correct order
Reversing the stack gives the topological order where each node appears before nodes depending on it.
Alternative Approaches
from collections import deque def kahn_topological_sort(graph): in_degree = {u: 0 for u in graph} for u in graph: for v in graph[u]: in_degree[v] += 1 queue = deque([u for u in graph if in_degree[u] == 0]) order = [] while queue: u = queue.popleft() order.append(u) for v in graph[u]: in_degree[v] -= 1 if in_degree[v] == 0: queue.append(v) if len(order) == len(graph): return order else: return [] # Cycle detected # Example usage graph = {'A': ['C'], 'B': ['C', 'D'], 'C': ['E'], 'D': ['F'], 'E': ['H', 'F'], 'F': ['G'], 'G': [], 'H': []} print(kahn_topological_sort(graph))
import networkx as nx g = nx.DiGraph() g.add_edges_from([('A', 'C'), ('B', 'C'), ('B', 'D'), ('C', 'E'), ('D', 'F'), ('E', 'H'), ('E', 'F'), ('F', 'G')]) order = list(nx.topological_sort(g)) print(order)
Complexity: O(V + E) time, O(V + E) space
Time Complexity
The algorithm visits each vertex and edge once, so the time is proportional to the number of vertices plus edges, O(V + E).
Space Complexity
Extra space is used for the visited set, recursion stack, and output list, all proportional to the number of vertices and edges.
Which Approach is Fastest?
Both DFS and Kahn's algorithm run in O(V + E) time; DFS is simpler to implement recursively, while Kahn's is iterative and can detect cycles.
| Approach | Time | Space | Best For |
|---|---|---|---|
| DFS-based Topological Sort | O(V + E) | O(V + E) | Simple recursive implementation |
| Kahn's Algorithm (BFS) | O(V + E) | O(V + E) | Cycle detection and iterative approach |
| networkx Library | Depends on implementation | Depends on implementation | Complex graphs and convenience |