Kahn、DFS --- 拓扑排序

拓扑排序算法

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

# 构造邻接表
import typing as t
from collections import deque


class Graph(object):

def __init__(self, vex: int):
"""
构造基本邻接表
:param vex: 顶点个数
"""
self.vex = vex
self.adj = [[] for _ in range(vex)]

def add_vex(self, s: int, m: int):
"""
构造边 s->t
"""
self.adj[s].append(m)

def topological_sorting_kahn(self) -> t.List:
"""
Kahn (卡恩) 算法, 根据入度是否为0去排序
时间复杂度为O(V+E), 空间复杂度为O(V)
算法思路:
1.遍历整个邻接表,根据逆链接表思维,构造入度集
2.利用双向队列,将当前轮满足入度为0的结点入队。
3.依次从队中出一个结点,将该结点指向的所有结点的入度边 - 1,若此时满足入度边==0, 则将对应结点入队。
4.重复执行2-3步骤,直到队空。得到拓扑排序结果,并且图中不存在环路。
"""
res = []
penetration = [0 for _ in range(self.vex)]
for i_r, r in enumerate(self.adj):
r: t.List
for i_c, c in enumerate(r):
penetration[c] += 1

q = deque()
# 第一轮,将入度为0的值入队
for i_j, j in enumerate(penetration):
if j == 0:
q.append(i_j)
while q:
node: int = q.popleft()
# 添加结点到排序结果集
res.append(node)
# 删除该结点及其所有的出度边 <==> (将该结点指向的所有结点的入度边 - 1)
for i_c, c in enumerate(self.adj[node]):
penetration[c] -= 1
if penetration[c] == 0:
q.append(c)
return res

def topological_sorting_dfs(self):
"""
TODO: DFS实现拓扑排序
算法思想:
1.根据邻接表构建出逆邻接表
2.DFS遍历逆邻接表中的顶点和对应的入度边结点,当某个结点没有入度结点,则将自身状态设置为-1,添加到拓扑排序数组中。
"""
pass


graph = Graph(6)
graph.add_vex(0, 2)
graph.add_vex(1, 2)
graph.add_vex(1, 4)
graph.add_vex(2, 3)
graph.add_vex(3, 5)
graph.add_vex(4, 5)
# Kahn算法
res_kahn = graph.topological_sorting_kahn()
print('Kahn算法', res_kahn)