刷题心得体会之拓扑排序的BFS和DFS方法(Leetcode 207 & 210)

最近本人终于做回了自己的老本行写代码,先从复习数据结构与算法刷题做起吧。工程/语言什么的也在学了,一并记录。由于老年腱鞘炎严重,不得不放弃传统手写而采用打字的方法。

题目是这样的:(来自Leetcode 210 课程表II)

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。

  • 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。

返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。

很容易就能想到,将所有的课程都看成一个节点,选修的先后关系看成一条有向边,我们可以得到一个有向图。在什么情况下不可能完成所有课程呢?最简单的情况是,课程1需要先修课程2,同时课程2需要先修课程1,形成闭环。那么,需要求得的结果便是:输出一组节点的顺序,使得在该排序中各边的先后顺序不能满足,同时当存在环时返回错误结果。

这是一个标准的拓扑排序问题。

百度百科里拓扑排序是这么描述它的:

对一个有向无环图 ( Directed Acyclic Graph 简称 DAG ) G 进行拓扑排序,是将 G
中所有顶点排成一个线性序列,使得图中任意一对顶点 u 和 v ,若边 < u , v > ∈ E ( G ),则 u 在线性序列中出现在 v
之前。通常,这样的线性序列称为满足拓扑次序 ( Topological Order )
的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
 

那么,如何求解呢?

有以下两种方法,分别需要用到queue以及stack两种数据结构,对应BFS算法以及DFS算法。

1、拓扑排序的BFS方法

首先,统计所有点的入度,选择其中入度为0的点,并将其加入一个队列之中。然后重复以下操作:

弹出队首元素,访问其所有邻节点并将其入度-1(等同于将节点从图中删除),此时若其邻节点在删除后有入度为0的,将其加入队列,直到队列为空。

若弹出的总元素数量少于总点数并且队列已经为空,说明图中存在环,不存在拓扑排序。

否则,则弹出的顺序即为该有向无环图的一个拓扑排序。

2、拓扑排序的DFS方法

首先,我们将节点的状态分为三种:

(1)待探索,说明此时DFS还没有扩展到这个节点。

(2)探索中,说明此时DFS已经扩展到了这个节点,但还没有搜索完成其所有分支。

(3)已探索,说明这个节点已经探索完了。

同样的,我们从任意一个入度为0的节点开始探索,如果不存在这样的节点那么也就不存在拓扑排序了。将其作为当前节点。同时,我们构建一个结果栈Stack。

若当前节点存在邻居,可能有三种情况:

(1)存在邻居未探索,此时深入并将该邻居标记为探索中,并作为当前节点。

(2)所有的邻居都已探索,此时将当前节点标记为已探索,将其压入Stack并回溯。

(3)存在一个邻居的状态为探索中,此时说明存在环,没有拓扑排序。

重复以上操作直至所有节点都压入Stack中。

此时将该结果栈的元素逐一弹出,即可得到该有向无环图的一种拓扑排序。

附:stl中stack、queue的用法

(1)stack

用法为stack<T> st ,主要接口有push(x)压入元素,pop()弹出元素(返回值为void),top()返回栈顶元素以及empty()和size()。位于头文件<stack>中

(2)queue

用法为queue<T> que ,主要接口有push(x)压入元素,pop()弹出队首元素,front()、end()分别取队首队尾元素以及empty()和size(),位于头文件<queue>中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kongtiao_hanry19

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

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

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

打赏作者

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

抵扣说明:

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

余额充值