大四复习:深入浅出解释拓扑排序

我在大二学习拓扑排序的时候,不是很明白,现在已经大四,抽时间复习一下拓扑排序。

什么是拓扑排序?

如何实现拓扑排序?

拓扑排序的拓展


什么是拓扑排序?

 首先拓扑排序的定义如下:

    拓扑排序是一种对有向无环图的顶点进行排序的方法。它的主要目的是产生一个顶点的线性序列,使得如果在图中存在一条从顶点 A 指向顶点 B 的边,则在排序结果中,顶点 A 出现在顶点 B 之前。

什么意思呢?我的理解拓扑排序 简单的说,就是 遍历一个没有环的有向图中, 按照箭头的顺序遍历节点。  

在上面一个有向无环图中,必须先访问a,才可以访问b或c;必须先访问b和c,才可以访问d。

所以,图的拓扑排序为a,b,c,d   或者a,c,b,d

如何实现拓扑排序?

这里我首先给出拓扑排序的算法,只有两步:

第一步:访问一个入度为0的节点

第二步:删除入度为0的节点以及从这个节点出去的所有边,继续执行1,直至图中没有节点。

以上面的图为例,a的入度为0,所以访问a,同时删除a和a的两个出边;此时,b和c节点的入度变为0。

因为b和c的入度都为0,我们可以随便选择一个访问,假设访问的b,删除b节点和它 的出边。

然后访问c节点,删除c节点和它 的出边,此时d节点入度为0,直接删除d节点,图中没有节点;

算法执行完毕。所以一个拓扑排序是  a,b,c,d。

如何来实现呢?我这里直接给出结论:使用BFS进行拓扑排序。

  1. 计算入度:对于图中的每个顶点,计算它的入度(即有多少边指向该顶点)。

  2. 初始化队列:创建一个队列,用于存储所有入度为 0 的顶点。这些顶点没有任何先决条件,可以立即处理。

  3. 拓扑排序

    • 当队列不为空时,从队列中移除一个顶点,并将其添加到拓扑排序的结果中。
    • 遍历该顶点的所有邻接顶点,将这些邻接顶点的入度减 1(因为它们的一个依赖已经被移除了)。
    • 如果任何邻接顶点的入度变为 0,则将其添加到队列中。
  4. 检查是否存在拓扑排序:如果排序结果中的顶点数量不等于图中的顶点总数,则说明图中存在环,因此不存在拓扑排序。

为什么可以使用BFS呢?(BFS算法不在这里多讲了。)

   BFS 以层级的方式遍历,在处理当前层的顶点之前,所有的前置顶点(即入度已被减至 0 的顶点)已经被处理。这种层级性保证了拓扑排序的正确性。

伪代码:

下面举一个具体的题目,leetcode207. 课程表

class Solution {
public:bool canFinish(int n, vector<vector<int>>& p) {vector<int>d(n,0);vector<vector<int>>g(n);for(int i=0;i<p.size();i++){g[p[i][0]].push_back(p[i][1]);d[p[i][1]]++;}queue<int>q;int cnt=0;for(int i=0;i<n;i++)if(d[i]==0)q.push(i);while(!q.empty()){int t=q.front();q.pop();cnt++;for(auto ne:g[t]){d[ne]--;if(d[ne]==0)q.push(ne);}}return cnt==n;}
};

上面代码使用C++来实现伪代码的功能,具体过程就不写了,和C++的语法有关系。

拓扑排序的拓展

拓扑排序的一个典型应用是解决具有依赖关系的任务调度问题。例如,在编译器中对程序模块进行编译时,必须先编译依赖模块,这种依赖关系就可以通过拓扑排序来解决。

  For example, suppose foo.c calls functions in libx.a and libz.a that call functions in liby.a. Then libx.a and libz.a must precede liby.a on the command line:

  unix> gcc foo.c libx.a libz.a liby.a

 Libraries can be repeated on the command line if necessary to satisfy the dependence requirements. For example, suppose foo.c calls a function in libx.a  that calls a function in liby.a that calls a function in libx.a. Then libx.a must be repeated on the command line:

  unix> gcc foo.c libx.a liby.a libx.a

摘自CSAPP

在编译过程中,模块间的依赖关系可以被视为一个有向图,其中每个模块代表一个顶点,依赖关系表示为有向边。例如,如果模块 A 依赖于模块 B,则会有一条从 B 指向 A 的边。

对于CSAPP的例子中,可以使用图来表示这个依赖关系:

拓扑排序还有一个重要的用途是检测循环依赖。如果模块间的依赖关系形成了一个环,那么将无法进行有效的拓扑排序。这在编译过程中是一个关键的检查点,因为循环依赖通常是编程错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/284422.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot中使用@Async实现异步调用

SpringBoot中使用Async实现异步调用 什么是异步调用?异步调用对应的是同步调用&#xff0c;同步调用指程序按照定义顺序依次执行&#xff0c;每一行程序都必须等待上 一行程序执行完成之后才能执行&#xff1b;异步调用指程序在顺序执行时&#xff0c;不等待异步调用的语句返…

LeedCode刷题---二分查找类问题

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、二分查找 题目链接&#xff1a;二分查找 题目描述 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一…

《LeetCode力扣练习》代码随想录——字符串(KMP算法学习补充——针对next数组构建的回退步骤进行解释)

《LeetCode力扣练习》代码随想录——字符串&#xff08;KMP算法学习补充——针对next数组构建的回退步骤进行解释&#xff09; 学习路径 代码随想录&#xff1a;28. 实现 strStr() CSDN&#xff1a;【详解】KMP算法——多图&#xff0c;多例子&#xff08;c语言&#xff09; …

unity—UGUI 点击按钮后,持续点击空格键会持续出发按钮

在unity开发当中&#xff0c;使用UGUI开发&#xff0c;无论是你代码绑定按钮事件&#xff0c;还是在Inspector窗口直接拖拽绑定的事件&#xff0c;点击按钮事件后&#xff0c;按空格键都会再次执行相关的方法。 默认情况下&#xff0c;Unity将空格键映射为UI按钮的Submit提交操…

【Hive_03】单行函数、聚合函数、窗口函数、自定义函数、炸裂函数

1、函数简介2、单行函数2.1 算术运算函数2.2 数值函数2.3 字符串函数&#xff08;1&#xff09;substring 截取字符串&#xff08;2&#xff09;replace 替换&#xff08;3&#xff09;regexp_replace 正则替换&#xff08;4&#xff09;regexp 正则匹配&#xff08;5&#xff…

如何应用基础故障编排?

基础故障编排是保障系统稳定性和可用性的关键环节。通过有效应用基础故障编排&#xff0c;组织能够更快速、更智能地应对系统故障&#xff0c;从而提升业务的可靠性和竞争力。本文将介绍如何应用基础故障编排! 1、选择合适的工具&#xff1a; 选择适合组织需求的基础故障编排工…

CUDA C:线程、线程块与线程格

相关阅读 CUDA Chttps://blog.csdn.net/weixin_45791458/category_12530616.html?spm1001.2014.3001.5482 第一百篇博客&#xff0c;写点不一样的。 当核函数在主机端被调用时&#xff0c;它会被转移到设备端执行&#xff0c;此时设备会根据核函数的调用格式产生对应的线程(…

linux:认识权限信息、修改权限(含演示)

权限细节 总共分为10个槽位 如下图所示&#xff1a; 序号1&#xff0c;表示文件、文件夹的权限控制信息 序号2&#xff0c;表示文件、文件夹所属用户 序号3&#xff0c;表示文件、文件夹所属用户组 举例:drwxr-xr-x表示: 1、这是一个文件夹&#xff0c;首字母d表示&#x…

C++面向对象(OOP)编程-模板

本文主要讲解C的模板&#xff0c;其中包括模板的分类&#xff0c;函数模板和类模板&#xff0c;以及类模板与友元函数关系引起的几种关系。强调提供代码来搞懂C模板这一泛型编程手段。 目录 1 C模板 2 模板的本质 3 模板分类 4 函数模板 4.1 函数模板定义格式 4.2 函数模…

欧盟健身单车出口BS EN ISO 20957安全报告测试

固定的训练器材.第10部分:带固定轮或无自由飞轮的训练自行车.附加特定安全要求和试验方法 作为欧洲固定式健身器材&#xff08;儿童用固定式健身器材不在此范围&#xff09;通用安全要求和测试方法的标准&#xff0c;涉及固定式健身器材精度、使用场所分类定义、稳定性、安全间…

SV-GWAS:基于首个番茄超级泛基因组图谱的结构变异

全基因组关联分析&#xff08;GWAS&#xff09;是定位性状相关基因的有力工具&#xff0c;被广泛用于识别影响表型变异的候选基因组位点。然而&#xff0c;通常GWAS的研究过程主要依赖于单核苷酸变异&#xff08;SNPs&#xff09;的信息与表型相关联&#xff0c;而忽略了具有更…

【WinDbg】学习以及在CTF中解题

1、Windbg介绍 Windbg是一款Window强大的调试器&#xff0c;可以调试0和3环的程序。 在实际开发中&#xff0c;可以调试我们的错误程序&#xff0c;从而定位关键代码&#xff0c;进行程序代码修复。 WinDbg 是一种调试器工具&#xff0c;由微软公司开发&#xff0c;用于分析…