拓扑排序:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,
是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),
则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序
(英语:Topological sorting):每个顶点出现且只出现一次;
若A在序列中排在B的前面,则在图中不存在从B到A的路径
结论:
(1)拓扑排序并不唯一
(2)不含回路的有向图(有向无环图)——一定存在拓扑排序。
Python 代码实现:
# v表示图中的各顶点,e表示两个顶点之间的边
def inDegree0(v,e):
# 如果顶点为空或者已经没有需要处理的顶点
if len(v) == 0:
return None
# 把v列表的内容复制给tmp变量,第一次tmp = ['a']
tmp = v[:]
# 遍历e列表中的每一个元组,第1个元组:('a','b'),
# 如果每个元组中[1]位置的值存在tmp列表的,则说明这个顶点入度不是0,也就说存在一条带方向指向其顶点的边
# 经历第一次遍历后,tmp列表的内容就是剩下入度是0的顶点
for i in e:
if i[1] in tmp:
tmp.remove(i[1])
# 如果不存在入度是0的列表,则说明存在环路,没法计算拓扑排序
if tmp == []:
return -1
for t in tmp:
# 对e列表中,如果包含'a'顶点的,则把其值替换为'toDel'
# ['toDel', 'toDel', ('b', 'c'), ('d', 'c'), ('d', 'e'), ('e', 'c')]
for i in range(len(e)):
if t in e[i]:
e[i] = 'toDel' # 占位,之后删掉
if e:
# set 和 dict 类似,也是一组 key 的集合,但是不存储 value. 由于 key 不重复
# set是一组数,无序,内容又不能重复,相当于去掉重复的'toDel'
# {'toDel', ('d', 'c'), ('b', 'c'), ('d', 'e'), ('e', 'c')}
eset = set(e)
# {('d', 'c'), ('b', 'c'), ('d', 'e'), ('e', 'c')}
eset.remove('toDel')
# 把集合转换为列表
# [('d', 'c'), ('b', 'c'), ('d', 'e'), ('e', 'c')]
e[:] = list(eset)
# 把刚才处理的a顶点从v列表中移除
# v=['b', 'c', 'd', 'e']
if v:
for t in tmp:
v.remove(t)
return tmp
def topoSort(v,e):
result = []
while True:
nodes = inDegree0(v, e)
if nodes == None:
break
if nodes == -1:
print('there\'s a circle.')
return None
# 用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。
result.extend(nodes)
return result
v=['a','b','c','d','e']
e=[('a','b'),('a','d'),('b','c'),('d','c'),('d','e'),('e','c')]
res=topoSort(v,e)
print(res)