简介
拓扑排序(Topological sorting)也是leetcode中的一类常见题型;他对于dependency任务做一个先后的排序,还是挺重要的。第一是build任务中我们需要这样的排序使得软件可以逐步build;另外我接触这个的时候是关于neural network compile的,在compile的过程中,哪个op可以先计算,哪个op需要等待,实际上也是用topological sorting。
伪代码
L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edge
while S is not empty do
remove a node n from S
add n to L
for each node m with an edge e from n to m do
remove edge e from the graph
if m has no other incoming edges then
insert m into S
if graph has edges then
return error (graph has at least one cycle)
else
return L (a topologically sorted order)
在这个伪代码中,S负责储存所有没有任何dependency的可执行任务。在把每个S node拿出来的过程中,我们假定S node已经被处理,来计算剩下的zero dependency node, 以此类推。如果最后发现还有剩余的edge(或者node), 那么就说明不存在topological sorting,也就是说graph有cycle。否则依次取出的S node就构成了topological sorting。
Python implementation
我们就以这道题举例:
L: list就好,毕竟只需要append。
S: 又需要append又需要popleft, 还是用deque吧
另外我们注意需要在for loop时迅速获得所有neighbor, 另外也需要remove edge。本质上我觉得是说需要两个map, 一个是source to target map以便获得所有的neighbor;一个是target to source map, 可以方便remove来检查是否所有的source都已被执行。最后附上这个问题我的python解答:
from collections import defaultdict, deque
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
source_target = defaultdict(set)
target_source = defaultdict(set)
for target, source in prerequisites:
source_target[source].add(target)
target_source[target].add(source)
empty = deque([i for i in range(numCourses) if i not in target_source])
topo_list = []
while empty:
source = empty.popleft()
topo_list.append(source)
for c_target in source_target[source]:
target_source[c_target].remove(source)
if len(target_source[c_target]) == 0:
empty.append(c_target)
if len(topo_list) == numCourses:
return topo_list
return []