排序-拓扑

拓扑排序:对一个有向无环图(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)

 

 
posted @ 2020-04-11 16:30  StudyNLP  阅读(243)  评论(0编辑  收藏  举报