Topological Sort
Visualize linear ordering of vertices in a directed acyclic graph (DAG)
Graph Editing
Simulation
ℹ️ No Start Node Needed
Unlike BFS, DFS, or Dijkstra, topological sort automatically processes all nodes in the graph. No start node selection is required.
Adjacency List
Current graph representation
What is Topological Sort?
Topological Sort is a linear ordering algorithm for vertices in a Directed Acyclic Graph (DAG) such that for every directed edge (u, v), vertex u comes before v in the ordering. It's impossible to perform topological sort on graphs with cycles, making it useful for cycle detection as well. Note: Edge weights are ignored by Topological Sort - it only considers the direction of edges, not their weights.
Two Main Approaches
There are two main algorithms for topological sort:
- Kahn's Algorithm (Queue-based): Processes nodes with no incoming edges (in-degree 0) first, then updates in-degrees of neighbors. More intuitive for understanding dependencies and better for parallel processing.
- DFS-based: Uses Depth-First Search to explore the graph deeply, then adds nodes to the order when backtracking. More visually engaging and better demonstrates the exploration pattern.
This visualization uses the DFS-based approach because it's more visually engaging. You can see the algorithm go deep into the graph and backtrack, making the exploration pattern clear and intuitive to follow.
How It Works (DFS-Based)
The DFS-based implementation works as follows:
- Start DFS from an unvisited node
- Go deep: recursively visit all unvisited neighbors first
- When backtracking (all neighbors processed), add the node to the topological order
- If a back edge is detected (visiting a node already in the DFS path), a cycle exists
- Repeat from step 1 for any remaining unvisited nodes
- Reverse the order to get the final topological sort
Implementation
Here's a Python implementation using DFS:
from typing import Dict, List, Optional
def topological_sort_dfs(graph: Dict[str, List[str]]) -> Optional[List[str]]:
"""
Perform topological sort on a directed acyclic graph (DAG) using DFS.
Returns a linear ordering of vertices such that for every directed edge (u, v),
vertex u comes before v in the ordering. If the graph contains cycles, returns None.
Uses DFS-based approach: explores deeply, then adds nodes to the order when
backtracking (after all neighbors are processed).
Args:
graph: Adjacency list representation of a directed graph.
Returns:
List of nodes in topological order, or None if a cycle is detected.
Time Complexity: O(V + E) where V is vertices and E is edges.
Space Complexity: O(V) for recursion stack and sets.
"""
visited: set[str] = set()
finished: set[str] = set()
result: List[str] = []
def dfs(node: str) -> bool:
"""Inner DFS function that detects cycles and builds topological order."""
if node in finished:
return True # Already processed
if node in visited:
return False # Back edge detected (cycle)
visited.add(node)
# Go deep: visit all neighbors first
for neighbor in graph.get(node, []):
if not dfs(neighbor):
return False # Cycle detected
# Backtrack: add to order when all neighbors processed
finished.add(node)
result.append(node)
return True
# Start DFS from all unvisited nodes
for node in graph:
if node not in finished:
if not dfs(node):
return None # Cycle detected
# Reverse to get topological order
result.reverse()
return result
# Example
graph = {'A': ['B', 'C'], 'B': ['D'], 'C': ['D'], 'D': []}
print(topological_sort_dfs(graph))
# ['A', 'B', 'C', 'D'] or ['A', 'C', 'B', 'D'] (multiple valid orders)Time Complexity
The time complexity is O(V + E), where V is the number of vertices and E is the number of edges. Each vertex and edge is processed exactly once, making it very efficient.
Edge Cases: If the graph contains cycles, the algorithm will detect them and indicate that not all nodes can be ordered. If the graph has disconnected components, the algorithm will process each component separately.
Real-World Applications
- Build systems: determining the order to compile source files with dependencies
- Task scheduling: scheduling tasks with prerequisites
- Course prerequisites: determining the order to take courses
- Package managers: resolving dependency installation order
- Event-driven systems: determining the order of event processing
- Cycle detection: detecting cycles in directed graphs