【数据结构】什么是拓扑排序—关于图的拓扑排序

简介: 【数据结构】什么是拓扑排序—关于图的拓扑排序

一、什么是拓扑排序?


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


二、拓扑排序:基本概念


问题:


假设以有向图表示一个工程的施工图或程序的数据流图,则图中不允许出现回路。

检查有向图是否存在回路的方法之一,是对有向图进行==拓扑排序==。有回路,不是存在拓扑排序;没有回路,存在拓扑排序

一个无环的有向图称为有向无环图(Directed Acycline Graph),简称为DAG图。


通常我们用一个有向图的顶点表示活动,边表示活动间先后关系,这样的有向图称为顶点活动网(Activity On Vertex network),简称AOV网。


工程是否顺利进行


完成整个工程所必须的最短时间


在AOV网表示工程的施工图,若出现==环==,标明该工程的施工设计图存在问题。


若AOV网表示的是数据流图,若出现==环==,标明存在死循环。


拓扑排序:对一个有向图构建拓扑序列的过程。


三、拓扑排序:分析


判断有向网是否存在有向环的一个方法:(对AOV网进行拓扑排序)


构造一个包含图中所有顶点的”拓扑排序序列“。


若在AOV网中存在一条从顶点u到顶点v的弧,则在==拓扑有序序列中顶点u必然优先于顶点v==。


若在AOV网中顶点u和顶点w之间没有弧,则在拓扑有序序列中,这两个顶点的先后次序关系可以==随意==


1b2a403e7ff04c4a8d63f30a52f53505.png


现有如下课程,并能够绘制下方有向图:


1b2a403e7ff04c4a8d63f30a52f53505.png


实例1:存在拓扑序列abcefdgh,说明不存在环


58402f99f4e34064becb800dd17c8869.png


实例2:不存在拓扑序列,说明存在环fdghf


6627c1345a794430a5084e6244475376.png


四、拓扑排序:步骤


步骤:

1. 在AOV网中选择一个没有前驱的顶点并输出


2. 从AOV网中删除该顶点以及从它出发的弧


3. 重复1和2直到AOV网为空(即已输出所有的顶点),或剩余子图中不存在没有前驱的顶点。后一种情况说明该AOV网中存在有向环。


算法要考虑的问题:


1. “没有前驱”如何判断


2. “删除顶点及以它为尾的弧”如何操作


解决方法:


1. 以==入度为零==作为没有前驱的量度


2. 算法中预设一个栈,用于保存当前出现的入度为零的顶点


3. 删除顶点及以它为尾的弧的这类操作,可用“弧头顶点的入度减1”的办法来替代。

afd40c2b55ef49cfa6c45064053876cf.png

五、拓扑排序:实现

由于拓扑排序中对图的主要操作是“找从顶点出发的弧”,并且AOV网在多数情况下是稀疏图,因此存储结构取==邻接表==为宜

public class TopologicalSort {
   // 拓扑排序
   public static boolean topologicalSort(ALGraph G) throws Exception {
      int count = 0;// 输出定点计数
      int[] indegree = findInDegree(G);// 求各顶点入度
      LinkStack S = new LinkStack();// 建零入度顶点栈
      for (int i = 0; i < G.getVexNum(); i++)
         if (indegree[i] == 0)// 入度为0者进栈
            S.push(i);
      while (!S.isEmpty()) {
         int i = (Integer) S.pop(); // 栈不空 取栈顶元素
         System.out.print(G.getVex(i) + " ");// 输出V号顶点 并 计数
         ++count;
         for (ArcNode arc = G.getVexs()[i].firstArc; arc != null; arc = arc
               .nextArc) {
            int k = arc.adjVex;
            if (--indegree[k] == 0)// 对i号顶点的每个邻接点的入度减1
               S.push(k);// 若入度减为0,则入栈
         }
      }
      if (count < G.getVexNum())
         return false;//该有向图有回路
      else
         return true;
   }
   //求各顶点入度  算法6.11
   public static int[] findInDegree(ALGraph G) throws Exception {
      int[] indegree = new int[G.getVexNum()];
      for (int i = 0; i < G.getVexNum(); i++)
         for (ArcNode arc = G.getVexs()[i].firstArc; arc != null; arc = arc
               .nextArc)
            ++indegree[arc.adjVex];// 入度增加1
      return indegree;
   }
   public static void main(String[] args) throws Exception {
      ALGraph G = GenerateGraph.generateALGraph();
      TopologicalSort.topologicalSort(G);
   }
}
// 调试结果:
// v1 v2 v3 v5 v7 v4 v6 v8 v9
  • 拓扑排序算法总的时间复杂度:O(n+e)


六、练习


试列出下图中,全部可能的拓扑有序序列:


image.png

相关文章
|
存储 机器学习/深度学习 算法
C 408—《数据结构》图、查找、排序专题考点(含解析)
408考研——《数据结构》图,查找和排序专题考点选择题汇总(含解析)。
1221 29
|
存储 人工智能 算法
【C++数据结构——内排序】二路归并排序(头歌实践教学平台习题)【合集】
本关任务是实现二路归并算法,即将两个有序数组合并为一个有序数组。主要内容包括: - **任务描述**:实现二路归并算法。 - **相关知识**: - 二路归并算法的基本概念。 - 算法步骤:通过比较两个有序数组的元素,依次将较小的元素放入新数组中。 - 代码示例(以 C++ 为例)。 - 时间复杂度为 O(m+n),空间复杂度为 O(m+n)。 - **测试说明**:平台会对你编写的代码进行测试,提供输入和输出示例。 - **通关代码**:提供了完整的 C++ 实现代码。 - **测试结果**:展示代码运行后的排序结果。 开始你的任务吧,祝你成功!
450 10
|
搜索推荐 算法 数据处理
【C++数据结构——内排序】希尔排序(头歌实践教学平台习题)【合集】
本文介绍了希尔排序算法的实现及相关知识。主要内容包括: - **任务描述**:实现希尔排序算法。 - **相关知识**: - 排序算法基础概念,如稳定性。 - 插入排序的基本思想和步骤。 - 间隔序列(增量序列)的概念及其在希尔排序中的应用。 - 算法的时间复杂度和空间复杂度分析。 - 代码实现技巧,如循环嵌套和索引计算。 - **测试说明**:提供了测试输入和输出示例,帮助验证代码正确性。 - **我的通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了代码运行的测试结果。 通过这些内容,读者可以全面了解希尔排序的原理和实现方法。
320 10
|
搜索推荐 C++
【C++数据结构——内排序】快速排序(头歌实践教学平台习题)【合集】
快速排序是一种高效的排序算法,基于分治策略。它的主要思想是通过选择一个基准元素(pivot),将数组划分成两部分。一部分的元素都小于等于基准元素,另一部分的元素都大于等于基准元素。然后对这两部分分别进行排序,最终使整个数组有序。(第一行是元素个数,第二行是待排序的原始关键字数据。本关任务:实现快速排序算法。开始你的任务吧,祝你成功!
371 7
|
搜索推荐 C++
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理(一)
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理
247 5
|
搜索推荐 索引
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理(二)
【初阶数据结构】深度解析七大常见排序|掌握底层逻辑与原理
252 4
|
存储 搜索推荐 算法
【用Java学习数据结构系列】七大排序要悄咪咪的学(直接插入,希尔,归并,选择,堆排,冒泡,快排)以及计数排序(非比较排序)
【用Java学习数据结构系列】七大排序要悄咪咪的学(直接插入,希尔,归并,选择,堆排,冒泡,快排)以及计数排序(非比较排序)
246 1
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
368 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
算法
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序

热门文章

最新文章