forked from keon/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtopological_sort_dfs.py
More file actions
113 lines (91 loc) · 3.04 KB
/
topological_sort_dfs.py
File metadata and controls
113 lines (91 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""
Topological Sort
Topological sort produces a linear ordering of vertices in a directed
acyclic graph (DAG) such that for every directed edge (u, v), vertex u
comes before v. Two implementations are provided: one recursive
(DFS-based) and one iterative.
Reference: https://en.wikipedia.org/wiki/Topological_sorting
Complexity:
Time: O(V + E)
Space: O(V)
"""
from __future__ import annotations
_GRAY, _BLACK = 0, 1
def top_sort_recursive(graph: dict[str, list[str]]) -> list[str]:
"""Return a topological ordering of *graph* using recursive DFS.
Args:
graph: Adjacency-list representation of a directed graph.
Returns:
A list of vertices in topological order.
Raises:
ValueError: If the graph contains a cycle.
Examples:
>>> top_sort_recursive({'a': ['b'], 'b': []})
['b', 'a']
"""
order: list[str] = []
enter = set(graph)
state: dict[str, int] = {}
def _dfs(node: str) -> None:
state[node] = _GRAY
for neighbour in graph.get(node, ()):
neighbour_state = state.get(neighbour)
if neighbour_state == _GRAY:
raise ValueError("cycle")
if neighbour_state == _BLACK:
continue
enter.discard(neighbour)
_dfs(neighbour)
order.append(node)
state[node] = _BLACK
while enter:
_dfs(enter.pop())
return order
def top_sort(graph: dict[str, list[str]]) -> list[str]:
"""Return a topological ordering of *graph* using an iterative approach.
Args:
graph: Adjacency-list representation of a directed graph.
Returns:
A list of vertices in topological order.
Raises:
ValueError: If the graph contains a cycle.
Examples:
>>> top_sort({'a': ['b'], 'b': []})
['b', 'a']
"""
order: list[str] = []
enter = set(graph)
state: dict[str, int] = {}
def _is_ready(node: str) -> bool:
neighbours = graph.get(node, ())
if len(neighbours) == 0:
return True
for neighbour in neighbours:
neighbour_state = state.get(neighbour)
if neighbour_state == _GRAY:
raise ValueError("cycle")
if neighbour_state != _BLACK:
return False
return True
while enter:
node = enter.pop()
stack: list[str] = []
while True:
state[node] = _GRAY
stack.append(node)
for neighbour in graph.get(node, ()):
neighbour_state = state.get(neighbour)
if neighbour_state == _GRAY:
raise ValueError("cycle")
if neighbour_state == _BLACK:
continue
enter.discard(neighbour)
stack.append(neighbour)
while stack and _is_ready(stack[-1]):
node = stack.pop()
order.append(node)
state[node] = _BLACK
if len(stack) == 0:
break
node = stack.pop()
return order