-
Notifications
You must be signed in to change notification settings - Fork 0
/
topsort.py
173 lines (144 loc) · 4.58 KB
/
topsort.py
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
def topsort(sorted, indegree_map):
"""Implement Kahn's topological sort, with recursion."""
# check length of indegree map is not 0.
# If so, return - graph must be sorted
if len(indegree_map.keys()) == 0:
return sorted
# get a node on which nothing depends
# get the first entry from indegree where value is 0
# if none, there's a cycle - tell user and return
chosen = None
for node, indegree in indegree_map.items():
if indegree == 0:
chosen = node
if chosen == None:
print("Cycle detected: no nodes have an indegree of 0.")
print("Topological sort not possible on this graph.")
return []
# add this node to sorted
sorted.append(chosen)
# remove it from the graph:
# remove edges - decrement any it has neighbours by 1 in indegree map
# remove node itself from indegree map
if len(adjacency_list[chosen]) != 0:
for neighbour in adjacency_list[chosen]:
indegree_map[neighbour] -= 1
indegree_map.pop(chosen)
return topsort(sorted, indegree_map)
# recursive results:
# adjacency_list = {
# 'A': ['B', 'C'],
# 'B': ['C'],
# 'C': []
# }
# calling topsort with following:
# adjacency_list: {'A': ['B', 'C'], 'B': ['C'], 'C': []}
# indegree_map: {'A': 0, 'B': 1, 'C': 2}
# gets correct order: ['A', 'B', 'C']
# adjacency_list = {
# 'A': ['B', 'C'],
# 'B': ['C', 'E'],
# 'C': ['D', 'E'],
# 'D': [],
# 'E': ['D']
# }
# calling topsort with following:
# adjacency_list: {'A': ['B', 'C'], 'B': ['C', 'E'], 'C': ['D', 'E'], 'D': [], 'E': ['D']}
# indegree_map: {'A': 0, 'B': 1, 'C': 2, 'D': 2, 'E': 2}
# gets correct order: ['A', 'B', 'C', 'E', 'D']
# adjacency_list = {
# 'A': []
# }
# calling topsort with following:
# adjacency_list: {'A': []}
# indegree_map: {'A': 0}
# gets correct order: ['A']
# adjacency_list = {
# 'A': ['B'],
# 'B': ['C'],
# 'C': ['A']
# }
# calling topsort with following:
# adjacency_list: {'A': ['B'], 'B': ['C'], 'C': ['A']}
# indegree_map: {'A': 1, 'B': 1, 'C': 1}
# Cycle detected: no nodes have an indegree of 0.
# Topological sort not possible on this graph.
# []
# create indegree map from this list
# key: node name, value: how many incoming edges it has
# set all nodes to 0 first
# indegree_map = {}
# for node in adjacency_list:
# indegree_map[node] = 0
# indegree_map = {k: 0 for k in adjacency_list}
# for node in adjacency_list:
# for neighbour in adjacency_list[node]:
# indegree_map[neighbour] += 1
# print('calling topsort with following:')
# print('adjacency_list: ', adjacency_list)
# print('indegree_map: ', indegree_map)
# result = topsort(sorted=[], indegree_map=indegree_map)
# print(result)
def topsort(adjacency_list):
"""Implement Kahn's topological sort, without recursion."""
# create indegree map from adjacency_list
indegree_map = {k: 0 for k in adjacency_list}
for node in adjacency_list:
for neighbour in adjacency_list[node]:
indegree_map[neighbour] += 1
sorted = []
while indegree_map.keys():
# get one with indegree of 0
# if none, print 'no topsort valid', return
chosen = None
for node, indegree in indegree_map.items():
if indegree == 0:
chosen = node
if chosen == None:
print("Cycle detected: no nodes have an indegree of 0.")
print("Topological sort not possible on this graph.")
return []
# add this node to sorted
sorted.append(chosen)
# remove it from the graph:
# remove edges - decrement any it has neighbours by 1 in indegree map
# remove node itself from indegree map
if len(adjacency_list[chosen]) != 0:
for neighbour in adjacency_list[chosen]:
indegree_map[neighbour] -= 1
indegree_map.pop(chosen)
return sorted
# iterative_result = topsort({
# 'A': ['B', 'C'],
# 'B': ['C'],
# 'C': []
# })
# print(iterative_result)
# gets correct result
# ['A', 'B', 'C']
# iterative_result = topsort({
# 'A': ['B', 'C'],
# 'B': ['C', 'E'],
# 'C': ['D', 'E'],
# 'D': [],
# 'E': ['D']
# })
# print(iterative_result)
# gets correct result
# ['A', 'B', 'C', 'E', 'D']
# iterative_result = topsort({
# 'A': []
# })
# print(iterative_result)
# gets correct result
# ['A']
iterative_result = topsort({
'A': ['B'],
'B': ['C'],
'C': ['A']
})
print(iterative_result)
# gets correct result
# Cycle detected: no nodes have an indegree of 0.
# Topological sort not possible on this graph.
# []