DAG-有向无环图-拓扑排序

news/2025/11/17 22:19:15/文章来源:https://www.cnblogs.com/2bjiujiu/p/19234644

1. 场景

通过当前节点与依赖节点列表描述一个有向无环图DAG节点依赖问题,适合流程图中节点依赖关系的定义,适合存在明确的依赖关系并且按依赖顺序执行的领域

  • 项目管理与任务调度
  • 工作流与审批流程

2. 数据描叙

  • name:描叙流程图中节点名称
  • dependencies: 描叙当前节点依赖的父级节点列表,dependencies为空则表示根节点
[{"dependencies": ["task-0711-1761200645304"],"name": "task-0711-1761200698814"},{"name": "task-0711-1761200645304"},{"dependencies": ["task-0711-1761200698814"],"name": "task-0711-1761204095457"},{"dependencies": ["task-0711-1761204095457"],"name": "task-0711-1761204132857"}
]

3. 输出从根节点到末尾节点(排好序的)

  • 方法1思路:
    • a. 首先遍历找出首节点
    • b. 找出首节点后依次找出后继节点添加到末尾
    • c. 时间复杂度:O(n^2) 空间复杂度: O(n)
    • d. 缺陷: 无法遍历出多节点的依赖的
task_dag = [{"dependencies": ["task-0711-1761200645304"],"name": "task-0711-1761200698814"},{"name": "task-0711-1761200645304"},{"dependencies": ["task-0711-1761200698814"],"name": "task-0711-1761204095457"},{"dependencies": ["task-0711-1761204095457"],"name": "task-0711-1761204132857"}
]def sort_dag(dag: list) -> []:nodes = []pre_node = Nonewhile len(dag) > 0:for index in range(len(dag)):deps = dag[index].get("dependencies", [])# 没有依赖的认为是第一个节点if not deps:nodes.insert(0, dag[index])pre_node = dag.pop(index)break# 存在依赖,依照顺序添加节点if pre_node and pre_node.get("name") in deps:pre_node = dag.pop(index)nodes.append(pre_node)breakreturn nodesif __name__ == '__main__':nodes = sort_dag(task_dag)print([n.get('name') for n in nodes])print(sort_dag(task_dag))pass
  • 方法2-拓扑排序思路
    • 依次建立拓扑的正向依赖和反向依赖
    • 计算正向依赖的入度,入度为0表示没有前置依赖,可以立即执行,进入队列
    • 执行完当前任务,减少其他依赖该任务的入度,将入度为0的任务添加到待执行任务列表
    • 时间复杂度 O(V+E) 空间复杂度 O(V+E) V表示任务数,E表示依赖边数
from collections import dequetask_dag = [{"dependencies": ["task-0711-1761200645304"],"name": "task-0711-1761200698814"},{"name": "task-0711-1761200645304"},{"dependencies": ["task-0711-1761204095457"],"name": "task-0711-1761204132857"},{"dependencies": ["task-0711-1761200698814"],"name": "task-0711-1761204095457"},
]def topology_sort(dag):# 1. 获取所有任务ID标识tasks = [task.get("name") for task in dag]# 2. 建立正向依赖:当前任务执行时,需要执行的前置任务(当前任务依赖前置任务完成)# 3. 建立反向依赖:当前任务执行时,需要执行的后置任务(后置任务依赖当前任务完成)dependencies_forward = {}dependencies_resolve = {}for node in dag:# 使用task_name作为唯一标识task_name = node.get("name")dependencies_forward[task_name] = node.get("dependencies", [])for dep in dependencies_forward[task_name]:# 校验是否存在不在dag中的任务if dep not in tasks:raise Exception(f"任务:{dep} 不在dag中,dag数据错误")if dep not in dependencies_resolve:dependencies_resolve[dep] = []dependencies_resolve[dep].append(task_name)# 4. 计算入度task_degree = {node.get("name"): len(node.get("dependencies", [])) for node in dag}# 5. 入度为0,进入待执行队里exec_queue = deque()for task, degree in task_degree.items():if degree == 0:exec_queue.append(task)# 6. 出待执行队列,执行任务,当前任务执行完成,意味着后置任务可以执行,更新当前任务关联的入度减去1sorted_task = []while exec_queue:current_task = exec_queue.popleft()# todo: 拿出具体任务执行的,这里是具体业务处理步骤# 简单的将当前入度为0立即执行的任务添加到执行顺序列表sorted_task.append(current_task)# 执行完成,减少任务的入度for dep in dependencies_resolve.get(current_task, []):task_degree[dep] -= 1if task_degree[dep] == 0:exec_queue.append(dep)# 判断是否存在环if len(sorted_task) != len(tasks):raise Exception(f"dag存在环")# 校验:# 1. 是否出现不在dag中的任务,dag图错误# 2. 是否存在dag环,存在dag环的话,入度始终不会为0return sorted_taskpassif __name__ == '__main__':print(topology_sort(task_dag))

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

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

相关文章

MySQL EXPLAIN中的key_len:精准掌握索引使用情况

深入解析MySQL执行计划中最关键的指标之一,助你快速定位索引优化点,提升查询性能!同时介绍了key_len计算的核心规则。MySQL系列文章 深入解析MySQL执行计划中最关键的指标之一,助你快速定位索引优化点,提升查询性…

1090 : 分解因数 25-11-17

|DFS|递归| 本题的dfs特点在于搜索的空间是动态的,因此需要找到可以利用到限制下一步递归的条件来进行空 间范围的缩小与框定。本题利用的是分解的最小因数,可以对下一步的遍历框定范围 #include<iostream> #i…

NOIP 模拟赛 9

NOIP 模拟赛总结 NOIP 模拟赛 9调了一整场的 T2,样例全过!只有 40 pts。QxQT1 卡门连续两场 T1 放数据结构了欸数据结构题,直接分块就行。 赛时没算时间复杂度,导致打了个暴力交上去以为是正解。 赛后半小时改完,…

Sora 2 Cameo多角色上传+Remix二创功能API接入教程,史低0.08/条

​ 你还记得Sora2推出的Cameo和Remix功能吗? Cameo(客串)是 Sora 2 推出的官方真人出镜功能,允许用户通过录制验证视频,将自己的面部、体型、声音特征提取并融合到 AI 生成的任意场景中,实现"真人演员+虚拟场景…

info linux

当然可以!你提到的 + #引号 + info linux + #引号 + 是一个在 Linux 系统中常用的命令,用于查看 Linux 内核的文档。它属于 info 命令集,是 man 命令的替代品,主要用于查看系统级的文档。 一、info 命令简介…

AWS云服务深度集成

第一部分:素材管理系统 - 分片上传与断点续传架构 在海量素材上传场景下,网络不稳定、文件巨大(数GB的视频/设计稿)是常态。直接简单上传会导致频繁失败且难以恢复。我们基于 AWS S3 Pre-signed URLs 和 Multipart…

httpd linux 启动

在 Linux 系统中,httpd 通常指的是 Apache HTTP Server,它是一个常用的 Web 服务器软件。如果你想要启动 Apache HTTP Server,可以使用以下几种常见方法:方法一:使用 systemd(适用于大多数现代 Linux 发行版) s…

浅谈 Manacher

问题引入 给定一个长度为 \(n\) 的字符串 \(s\),保证 \(s\) 只由小写字母组成,要求计算出 \(s\) 中最长的连续回文子串的长度。 乍一看,诶我会 \(O(n^3)\) 做法!枚举左右端点然后暴力判断就行。 但是这也太慢了吧!…

第28天(简单题中等题 二分查找)

打卡第二十八天 1道简单题+2道中等题题目:思路:双指针+二分查找 代码: class Solution { public:vector<int> kthSmallestPrimeFraction(vector<int>& arr, int k) {const int n = (int)arr.size();//…

基于MIMO系统的SCMA稀疏码多址接入和MPA消息传递算法matlab仿真

1.算法运行效果图预览2.算法运行软件版本 matlab2022a/matlab2024b 3.部分核心程序 (完整版代码包含详细中文注释和操作步骤视频)................................................................r = de2bi(X, l…

Node.js服务稳定性保障:从热更新到高可用体系

好的,这些问题深入到了Node.js后端架构的核心。下面我将为您系统地拆解这些挑战和我们的解决方案。Node.js服务稳定性保障:从热更新到高可用体系 第一部分:渲染服务的热更新原理与高并发保障 我们的官网/商城渲染服…

一次尝试,3个小时90元的主机游玩和F1电影

一次尝试,3个小时90元的主机游玩和F1电影2025年11月16日 星期日 早上去中影烽禾影城泛悦奥莱店(马房山店),花了90块钱,在PS5上面玩了将近三个小时的风之旅人,比我想象之中的还要可怕,我的忘性大的吓人,除了那个红…

NOIP 模拟赛 8

呜呜呜,直接叫 T1 模拟赛吧。NOIP 模拟赛总结 NOIP 模拟赛 8呜呜呜,直接叫 T1 模拟赛吧。T1 王哥与荷塘(fish) 发现要求的是曼哈顿距离的最远点对。 根据 HZ战神 王战普老师的教导可知。 任意两点的曼哈顿距离可以…

静态路由的配置

11.17配置静态路由实验1、拓扑结构:两台PC机,两台交换机Router 2、连线:PC与Router交叉线连接FastEthernet0/0 Router之间DCE串口线连接Serial2/0口 3、打开接口 Router0和Router1 enable //进入特权模式 config…

读书笔记:“外部表”的进阶使用,它主要解决了三个核心问题:如何切换文件、多用户怎么办,以及一个非常酷的玩法——把系统命令变成表。

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。本文为个人学…

[CF 2166D] Marble Council

思路 肯定是在值域上处理, 类似今年 S T4 的将与未扫描部分相关的部分单独统计 定义 \(c_x\) 为 \(a_i = x\) 的数量 考虑 \(f_{i, j, k}\) 表示考虑到数字 \(i\), 当前要求容量到 \(j\), 当前容量为 \(k\) 的方案数 \…

DP 复习

背包 DP 背包 dp 解决形如用一些物品,有一些限制,装满这个容量的方案/最小代价。 四种板子01背包,循环从高到低 完全背包,循环从低到高 多重背包,二进制分组(低到高)然后01背包 分组背包,每组在最内层,外层跑…

一段话 UOJ

UOJ 比赛胡做UOJ Test Round #1 开始了。 vfk的数据 除了编号的前后缀都一样,长度为第一关键字,字典序为第二关键字排序即可。 这样不需要进行字符串的处理。 record pyx的难题 假定 \(p_x=-1\) 是从 \(S\) 开始考虑…

PG系列:在 ​​psql​​ 客户端中定义参数与动态赋值

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。作为一名长期…

CF1375G Tree Modification 题解

\(\text{CF1375G Tree Modification 题解}\) 相当能引起思考的题目,这里给出两种方法。 首先这个操作相当于把一个节点的孙子及这个孙子的儿子拽上来作为它的儿子,这样的话从下往上合并一定是最优的。那么容易想到的…