拓扑排序(Kahn算法和DFS算法)

一 引言

玩过塞尔达的小伙伴都知道,要想救公主,要经历以下的步骤(当然也可以拿到滑翔伞直接打boss........),其中拔出大师之剑不光要解锁迷雾森林,还要解锁神庙增加心之容器,也就是说两个条件必须同时满足,之后再解放四神兽,击败盖侬救出公主

可以看出任务之间有先后顺序的,图中的任务有的难,有的简单,但是不重要,拓扑只考虑它们之间的先后依赖关系,而不考虑它们自身的属性,这也是为什么叫做拓扑排序的原因。拓扑排序是指对于一个有向无环图(DAG, Directed Acyclic Graph),找到一种线性排列的方式,使得对于每一条从顶点u到v的有向边(u, v),u在排序结果中都出现在v之前。换句话说,它是一种将图中的节点按某种顺序排列的方法,以确保所有的依赖关系都能得到满足。

为什么必须是无环图?

拓扑排序要求对于每条有向边 (u, v),顶点 u 必须出现在顶点 v 之前。如果图中存在环,则环内的所有顶点都相互依赖,没有一个明确的起点或终点可以开始排序。换句话说,在环内不存在任何一个顶点可以在另一个顶点之前处理。

二 应用

拓扑排序在许多领域都有广泛的应用,尤其是在处理依赖关系方面:

1 任务调度:例如项目管理、构建系统中的任务依赖解析。
2 编译器优化:确定代码模块或函数之间的调用顺序。 
3 网络路由中的优先级处理等领域
4 包管理器中的依赖解析:如npm、Maven等工具中软件包安装顺序的确定。
5 课程安排:规划学习路径,确保先修课程被正确安排在后续课程之前。
6 数据库迁移脚本生成:保证表创建、修改等操作按照正确的依赖顺序执行。
7 游戏开发:比如资源加载顺序、关卡解锁条件、技能树等。

三 实现

 Kahn算法

1 思路

既然是处理依赖关系,那么就可以从入度为0的节点开始,像剥洋葱一样一层一层深入到最里层。比如对于开头说的塞尔达,

(1) 先找到所有入度(即指向该节点的边的数量)为0的任务,发现是解锁神庙和解锁迷雾森林

(2) 一个一个处理入度为0的任务,处理的方式就是将入度为0的任务和它的边删除,同时将它指向的任务的入度减去1

(3) 解锁神庙处理完以后,入度为0的任务只剩下解锁迷雾森林,同时拿到大师之剑的任务的入度变成1。再处理解锁迷雾森林后,拿到大师之剑的入度变成0,这时候就该处理拿到大师之剑的任务。

(4)依次类推,直到救出塞尔达的入度为0,处理完成。通过迭代地移除入度为0的节点来构建排序结果被称作Kahn算法。

2 步骤

1 计算每个节点的入度
2 初始化一个队列,包含所有入度为0的节点。
3 从队列中取出一个节点,将其加入拓扑排序的结果列表,并减少其所有邻接节点的入度。
4 如果某个邻接节点的入度变为0,则将其加入队列。
5 重复步骤3-4直到队列为空。
6 如果结果列表中的节点数量等于原始图中的节点数,则返回结果;否则,图中存在环。<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不良人-小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值