拓扑排序 python实现

拓扑排序是指在有向无环图中,把所有结点按照一定的排序排成一列,使得左边的点都指向右边的点。
一般有两种方法做拓扑排序

  1. Kahn算法 / BFS广搜
    用一个一维数组inDegrees记录每个结点的入度。再用一个数据结构q(随意都可以,数组,栈,列表等等)根据inDegrees表,找所有入度为0的结点存入。遍历q,一个一个pop出,每pop出一个要记录下来,把该结点指向的所有点的入度减1(更新入度表)。如果为更新后的点入度为0就存进q。再循环操作,直到q为空。如果路径长度不够或者入度表不是全0,说明该图不是有向无环图(可判断有向图是否有环)。
    tips:如果是要打印字典序排序,就用优先列表正序存入度为0的结点。

  2. DFS深搜 (后序遍历)
    从任意一个未被访问的结点出发做深搜后序遍历。遍历所有结点,回溯前记录结点,最后路径再倒序一下就是正确的拓扑排序(或者建图的时候就把边的方向倒了,最后得到的排序不用倒)。如果有多个子图,要多次深搜,直到所有结点都被访问完(所有子图都搜完)得到多个子序列,再拼接一起就是答案。
    tips:字典序排序想不到,哪位大神可以说说dfs的思路?如果单个子图字典序行得通,那么最后把各子序列归并一下就好了。

对于DFS方法有人可能疑惑为什么要回溯前才记录(要用后序遍历的原因),而且为什么可以从任一点开始?

  • 能回溯的点说明已经把子代遍历完,确定是最后的了,于是可以记录下来,得到一个倒序记录。拓扑排序的一个节点可能有多个父结点,所以无法确定某点为先。如下图,如果我已遍历得0–>2顺序,但是在2之前还有一个点1,明显不对,先序遍历行不通。这是由结构所决定的,不同于树,拓扑排序分支节点之间可能有联系的,导致一个节点可能有多个父结点,故没有严格的先后顺序。而从后往前记录,因为节点遍历完分支,故不怕节点再指向任何节点也就不可能指回前面节点,后序遍历可行。如果要对一个二叉树做拓扑排序,代码与此大同小异,二叉树只有两个子结点,无需for循环而已。
  • 从任意点开始遍历都行,是因为后序遍历保证了已记录的就是最靠后的了。后面记录的结点肯定不会后于已记录的结点。比如先从3开始搜,3->4(记录下4->3),然后无论从哪个结点再开始搜,都不会打乱顺序了,012都是先于3(可能的记录下为4->3->5->2->1->0->6->7),567放3前面也没事(可能的记录为4->3->6->7->5->2->1->0)。

样例图片
在这里插入图片描述
python代码:

from queue import PriorityQueue as pQueue
import sys

sys.setrecursionlimit(100000)


# ---------------------------方法1: Kahn方法 / BFS------------------------------
# 这是最常见的拓扑排序,0入度集合可以用队列,栈等等,只要能存储0入度的点就行
# 这里用了队列,其实就是跟广搜差不多,入度为0的才入队
def ts_bfs(inDegrees, graph):
    n = len(graph)
    result = []
    q = []
    vis = [False] * n
    for i, inDegree in enumerate(inDegrees)<
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值