🎯 DFS-based Topological Sort
DFS Algorithm
Uses post-order traversal with a stack to build the topological order.
- 🔍 Visit each unvisited vertex
- 📚 Recursively visit all neighbors
- 🎯 Add vertex to stack after visiting all neighbors
- ↩️ Reverse the stack for final order
Implementation with Cycle Detection
def topological_sort_dfs(vertices, edges):
"""
DFS-based topological sorting
Time: O(V + E), Space: O(V)
"""
# Build adjacency list
graph = defaultdict(list)
for u, v in edges:
graph[u].append(v)
# Color states: WHITE (0) = unvisited, GRAY (1) = visiting, BLACK (2) = visited
color = {v: 0 for v in vertices}
stack = []
has_cycle = False
def dfs(vertex):
nonlocal has_cycle
if has_cycle:
return
color[vertex] = 1 # Mark as visiting (GRAY)
for neighbor in graph[vertex]:
if color[neighbor] == 1: # Back edge (cycle detected)
has_cycle = True
return
elif color[neighbor] == 0: # Unvisited
dfs(neighbor)
color[vertex] = 2 # Mark as visited (BLACK)
stack.append(vertex) # Add to stack in post-order
# Visit all vertices
for vertex in vertices:
if color[vertex] == 0:
dfs(vertex)
if has_cycle:
return None # Cycle detected
return stack[::-1] # Reverse for topological order
# Example with cycle detection
vertices = ['A', 'B', 'C', 'D']
edges = [('A', 'B'), ('B', 'C'), ('C', 'D')]
print(topological_sort_dfs(vertices, edges))
# Output: ['A', 'B', 'C', 'D']
# Example with cycle
edges_with_cycle = [('A', 'B'), ('B', 'C'), ('C', 'A')]
print(topological_sort_dfs(['A', 'B', 'C'], edges_with_cycle))
# Output: None (cycle detected)
All Topological Sorts
def all_topological_sorts(vertices, edges):
"""
Generate all possible topological sorts
"""
graph = defaultdict(list)
in_degree = {v: 0 for v in vertices}
for u, v in edges:
graph[u].append(v)
in_degree[v] += 1
all_sorts = []
def backtrack(current_sort, remaining):
if not remaining:
all_sorts.append(current_sort[:])
return
# Try each vertex with in-degree 0
for vertex in remaining:
if in_degree[vertex] == 0:
# Choose vertex
current_sort.append(vertex)
new_remaining = remaining - {vertex}
# Update in-degrees
for neighbor in graph[vertex]:
in_degree[neighbor] -= 1
# Recurse
backtrack(current_sort, new_remaining)
# Backtrack
for neighbor in graph[vertex]:
in_degree[neighbor] += 1
current_sort.pop()
backtrack([], set(vertices))
return all_sorts
# Example
vertices = ['A', 'B', 'C']
edges = [('A', 'C')]
print(all_topological_sorts(vertices, edges))
# Output: [['A', 'B', 'C'], ['B', 'A', 'C']]