Extracted from here we got a minimal iterative dfs routine, i call it minimal because you can hardly simplify the code further:
def iterative_dfs(graph, star
I was also trying to simplify this so I came up with this:
from collections import deque
def dfs(graph, source, stack, visited):
visited.add(source)
for neighbour in graph[source]:
if neighbour not in visited:
dfs(graph, neighbour, stack, visited)
stack.appendleft(source)
def topological_sort_of(graph):
stack = deque()
visited = set()
for vertex in graph.keys():
if vertex not in visited:
dfs(graph, vertex, stack, visited)
return stack
if __name__ == "__main__":
graph = {
0: [1, 2],
1: [2, 5],
2: [3],
3: [],
4: [],
5: [3, 4],
6: [1, 5],
}
topological_sort = topological_sort_of(graph)
print(topological_sort)
Function dfs
(Depth First Search) is used to create the stack of finishing times for every vertex in the graph. Finishing time here means that the element pushed into the stack first, is the first vertex where all of its neighbours are fully explored (no other unvisited neighbours are available to explore from that vertex) and the last element pushed into the stack is the last vertex where all of its neighbours are fully explored.
The stack is now simply the topological sort.
Using a Python set for visited
provides constant membership checking and using deque
as a stack provides constant-time left insertion as well.
The high-level idea was inspired by CLRS [1].
[1] Cormen, Thomas H., et al. Introduction to algorithms. MIT Press, 2009.