前言
写在前面的话:数据结构与算法。
对于初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到同tag前面的内容,包括具体数据结构的应用,所使用到的数据结构,也是自己构建的,未使用系统的库文件,因此,建议这类小伙伴们按顺序进行学习;
对于想查询有关资料的小伙伴们,可以选择性地浏览。希望大家都能有所收获~
如何理解拓扑排序?
上一篇笔者介绍了图中两种重要的搜索算法-----BFS和DFS
,这一章,我们来了解一下图中的另一个重要知识:拓扑排序。许多人可能听说过这个术语,但是不太了解,它是一种排序算法吗?不是。 简单来说,拓扑排序,实质是对有向图的节点排成一个线性序列。
为什么会出现拓扑排序这一概念呢?我们来举个例子,假如你想学习jeecg-boot
这个框架,你可能需要学习以下内容:
java, html, css, javascript, vue, ant-design-vue, springboot, jeecgboot…
你会发现,这些东西,学习的顺序是有一定限制的,比如,你必须先学html
,之后才能学vue
;你必须先学习springboot
,之后才能学习jeecgboot
。
这样,我们自然就会问,我按怎样的顺序学习这些内容才是合理的呢?其实,我们可以用一个简单的有向图来表示学习的顺序关系:
从这个流程图中,我们能够清晰地看出,应该先学什么,后学什么。 进一步,如果你给一个小白介绍jeecg-boot
框架应该如何学,你只需跟他说,按照以下路线学习就OK了:
java–>html–>css–>javascript–>vue–>springboot–>ant–>jeecg
上面这个序列可以看成是流程图按照某种遍历方式进行遍历得到的一个结果序列。这种遍历方式,咱取个名字,就称为拓扑排序
;得到的线性序列,称为拓扑序列
。
从上述的过程来看,拓扑序列是不唯一的,比如:
java–>html–>javascript–>css–>vue–>springboot–>ant–>jeecg
java–>html–>javascript–>css–>springboot–>vue–>ant–>jeecg
均是正确的拓扑序列
。
将上述的流程图抽象成一般的有向图,就引入了图中的拓扑排序以及拓扑序列的概念。
拓扑图示示例
下面我们来看,对于图,其进行拓扑排序的步骤:
- 从有向图中找出没有前驱节点的节点,直接输出(如果有多个,不考虑顺序,均输出)
- 删除以该节点为起点的所有边(如果节点不止一个,均删除)
- 重复上述过程,直至最后一个节点被输出。(如果还有节点未输出,说明有环!)
我们还是用一系列图示来帮助理解拓扑排序的步骤:
首先,找到没有前驱节点的节点A
,B
,将其输出至序列(或者使用优先队列存储起来),并删除以节点A
,B
为起点的所有边:
接着,继续找没有前驱节点的节点C
,D
,G
,将其输出至序列,并删除以节点C
,D
,G
为起点的所有边:
重复以上操作。E
,F
无前驱节点,将其输出至序列,并删除以节点E
,F
为起点的所有边:
最后,节点H
无前驱节点,将其输出至序列,节点H
无边,遍历结束。
好的关于图的拓扑排序,就介绍到这里了。有兴趣的小伙伴们可以去查询更多资料了解拓扑排序的应用。到这,关于图的三大算法,已经全部介绍完毕了。
下一章,我们开始用代码来实现图的三大算法。