专栏首页青玉伏案算法与数据结构(七) AOV网的拓扑排序(Swift版)

算法与数据结构(七) AOV网的拓扑排序(Swift版)

今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的。拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍:

AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划和实施过程,一个工程常被分为多个小的子工程,这些子工程被称为活动(Activity),在有向图中若以顶点表示活动,有向边表示活动之间的先后关系,这样的图简称为AOV网。

说的简单点,AOV网就是表示一个工程中某些子项的先后顺序。就拿工地搬砖来说吧,只有砖厂送来砖,工人才能搬。那么砖厂送砖就是搬砖的前提。先这么一聊,下方会给出详细的介绍。废话少说进入今天的主题。

一、AOV网与拓扑排序

本篇博客我们先聊一下AOV网和拓扑排序的关系,下方是我们列举的一个非常简单的例子,当然下方的这个图就是一个简单的AOV图,麻雀虽小,五脏俱全。在下方的AOV图中,送砖和找人是并列的,先执行谁都行。不过搬砖的前提是即送完了砖也找完了人,然后就可以开始搬砖了,所以送砖和找人就是搬砖的前提。那么让搬砖这件事情顺利进行下去的顺序有"送砖->找人->搬砖"或者“找人->送砖->搬砖”这两个序列,而这两个序列都是拓扑序列。

生成“送砖->找人->搬砖”这个序列的过程我们称之为拓扑排序。如果非得说的官方和抽象点,那么还是引用拓扑排序的定义吧,下方就是拓扑排序的定义:

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

 上面这个定义就比较抽象了,当然还是我们搬砖的例子好理解一些。在有向无环图中的结点如果有入度的话,那么就说明该结点优先级要低于那些可以到达改点的结点。而那些没有入度的结点的优先级就比较高,这些结点的完成不依赖与其他结点。这样说如果有些抽象的话,那么我们就看下方拓扑排序详细的示例图。

二、拓扑排序示意图

本部分我们将会给出拓扑排序详细的示意图。拓扑排序实现是依赖于栈与队列的数据结构,栈用来暂存那些入度为0的结点,而队列负责存储已经生成的拓扑序列。因为前几篇关于图的博客,我们都使用了相同的图结构。本篇博客也不例外,我们依然会使用之前的有向图,因为之前的图是有向无环图,所以是可以生成拓扑序列的。下方就是要生成拓扑序列的有向无环图。

在下方的有向无环图每个结点上有一个绿色的数字,该数字记录的就是该结点的入度。入度为零,那么该数字就是0,如果入度为1,那么该数字就是1。

下方是下图拓扑排序每一步的示意图。接下来我们将会给出下方每一步示意图的详细解说。

  • (1):首先将图中入度为0的结点入栈,因为此图中只有A结点的入度为0,所以我们将A入栈。
  • (2):将A从栈中Pop到我们的拓扑队列中,将那些以A发出的边为入度的结点的度数减一。对于此示例来说也就是将B和F入度减1. 因为B和F的入度数减一后成了0,所以也将B, F这两结点入栈。
  • (3):将F从栈中Pop到拓扑队列中,因为图中有F->G和F->E两条边,所以将G和E的入度数减一。因为E的入度数减一后为0,所以将E入栈。
  • (4):将E从栈中Pop到拓扑队列中,因为图中E->H和E->D两条边,所以讲H和D的两个结点的入度减一。两个结点减一操作后没有入度为零的节点,所以本步没有结点入栈。
  • (5):接着从栈中Pop结点到拓扑队列中,将B结点Pop出栈入拓扑队列。因为C、I、G结点与B相连,B添加进拓扑序列后,这三个结点的入度都减一。C和G的入度减一后为0,所以将其加入栈中。
  • (6):将C从栈中pop到拓扑队列中,与C相连的结点是I和D, 将这两个结点的入度减1。I的入度减一后为0,将其Push到栈中暂存。
  • (7):将I结点从栈中pop到拓扑队列中,D与I相连,将D的入度再次减一。本轮没有要入栈的结点。
  • (8):将G从栈中pop到拓扑队列中,G与H和D相连,将D与H的入度减一。H的入度减一操作后入度为零将其入栈。
  • (9):将H从站中pop到拓扑队列中,D与H相连,将D的入度减一,减一后为0,所以将D入栈。
  • (10):将D从栈中pop到拓扑队列中,此刻栈中为空,拓扑序列生成完毕。

上面这些步骤已经很详细了,上面这些步骤搞明白后,给出代码实现就简单多了。下方我们会给出具体的代码实现。

三、拓扑排序的代码实现

讲完概念和原理后,接下来我们就要开始实践了。本部分就会给出具体的代码实现,当然我们依然采用Swift语言来做。首先我们创建要依赖的队列和栈,然后再构建有向图的邻接链表,最后给出拓扑排序的代码实现。进入本部分的主题:

1.队列与栈

接下来我们就要实现拓扑序列生成时要使用的栈与队列,关于栈与队列本篇博客就不做过多的赘述了,因为我们之前已经对栈与队列做了详细的介绍。关于栈与队列更详细的内容请查看之前的博客《栈与队列的线性和链式表示(Swift面向对象版)》。

下方这段代码段就是我们本篇博客要使用的栈的类,当然是简化版的,也就是对Array做了一个简单的封装。栈中存储的数据类型是我们邻接链表的结点。具体代码如下所示。

下方则是我们存储拓扑序列的队列,当然也是基于Array的简单封装。 

2.有向图的构建

接下来我们来创建我们的有向图。本篇博客所使用的有向图我们是使用邻接链表来表示的。下方这段代码段就是邻接链表的结点,当然在之前不知一篇博客中我们使用到了下方这个结点。本篇博客中的weightNumber不仅仅只存边的权值,在数组中的结点的weightNumber我们用来存储该结点的入度。

下方这段代码就是有向图的创建,在网邻接链表上挂入结点时,要讲被挂入的结点的入度加1即可。因为下方代码与之前图的创建的代码类似,在此就不做过多赘述了。

下方这两个截图则是上述代码段的输入和输出。根据输出的结果我们不难看出我们所创建的图就是一个有向图。

3、拓扑序列的生成

接下来就是我们本篇博客代码实现的核心了。我们将基于上面创建的AOV网来生成拓扑序列。其实下方生成拓扑序列的代码就是上述示例描述的具体实现。接下来我们将具体的说下下方这段拓扑排序的代码。主要概括起来分为下方三步:

  • (1):首先初始化我们所需要的栈,然后遍历AOV网中所有的结点,将入度为0的结点添加到我们的栈中暂存。
  • (2):循环将我们栈中的元素添加到拓扑队列中。每从栈中Pop出一个结点就把与该结点相连的结点的入度减1,如果减一后该结点的度数为0则将其入栈。然后继续下一轮的循环。
  • (3):当栈中没有暂存的结点后,说明拓扑序列生成完毕。如果拓扑队列中的元素要小于图结点的个数,那么说明图中存在环路,不能生成相应的拓扑序列。

下方截图就是我们之前创建的有向图所生成的拓扑序列,如下所示:

至此,我们本篇博客的内容也就结束了,下方依然是我们本篇博客所涉及Demo的分享链接,如下所示:

github分享链接:https://github.com/lizelu/DataStruct-Swift/tree/master/TopoLogicalSort

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Web前端上万字的知识总结

    下面是自己学HTML+DIV+CSS+JS时的学习笔记,给大家分享以下,相互学习。大二时候寒假在家无聊的时候想做点事,总结了一下web前端基础的东西,下面的每...

    lizelu
  • web前端基础知识总结

    上个寒假总结的web前端的一些知识点给大家分享一下 1、<html>和</html> 标签限定了文档的开始和结束点。 属性: (1)  dir: 文本的显示方向...

    lizelu
  • 算法与数据结构(二) 栈与队列的线性和链式表示(Swift版)

    数据结构中的栈与队列还是经常使用的,栈与队列其实就是线性表的一种应用。因为线性队列分为顺序存储和链式存储,所以栈可以分为链栈和顺序栈,队列也可分为顺序队列和链队...

    lizelu
  • Graph-Bert:没有我Attention解决不了的

    最近要做一个图相关的项目,之前没怎么接触过图网络,就从头开始学习了一下,后面有时间也会整理分享。这里顺便推荐一下清华大学唐杰老师的一个分享:「图表示学习和图神经...

    kaiyuan
  • 2-6 链表逆序

    A -> C -> B -> D -> E -> F -> null #将上面 B后的C 插入到A后面

    TeeyoHuang
  • ArtTemplate模板的使用(二)

    上一篇文章说了artTemplate的最基本的用法,它还有一个方法就是使用模板的方式,template的compile();

    无邪Z
  • SQL*PLUS技巧:生成易读的HTML报表

    TeacherWhat
  • 数据结构 键树查找法

    键树查找法 又称数字查找树(根节点子树>=2个),键树节点存储的不是某个关键字,而是组成关键字的单个符号。

    Debug客栈
  • 算法:优先队列-理论

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    营琪
  • 线性表的链式存储结构的实现及其应用(C/C++实现)

    存档----------- 1 #include <iostream.h> 2 typedef char ElemType; 3 #include "Li...

    Angel_Kitty

扫码关注云+社区

领取腾讯云代金券