当前位置: 首页 > news >正文

【算法】小白也能懂 · 第 16 节:拓扑排序

在现实生活中,很多任务之间存在依赖关系。比如:你必须先学完 C++ 基础,才能学 STL;必须先编译源文件,才能链接成可执行程序。

拓扑排序就是解决这类「依赖关系排序」问题的经典算法。

1. 什么是拓扑排序?

1.1 问题定义

给定一个有向无环图(DAG),将图中的所有顶点排成一个线性序列,使得对于图中任意一条边 (u, v),顶点 u 在序列中都出现在顶点 v 之前。

用大白话说:把有依赖关系的任务排个顺序,确保每个任务都在它依赖的任务之后执行

1.2 生活中的例子

选课系统

数据结构 → 算法设计 → 高级算法 ↓ ↓ 操作系统 → 编译原理

这个依赖关系的拓扑排序结果可以是:

  • 数据结构 → 操作系统 → 算法设计 → 编译原理 → 高级算法
  • 数据结构 → 算法设计 → 操作系统 → 编译原理 → 高级算法

注意:拓扑排序的结果可能不唯一,只要满足依赖关系即可。

1.3 关键性质

  • 只有有向无环图(DAG)才有拓扑排序
  • 如果图中有环,则不存在拓扑排序(循环依赖无法解决)
  • 拓扑排序可以用来检测图中是否有环

2. Kahn 算法(BFS 方法)

2.1 核心思想

Kahn 算法的思路非常直观:

  1. 找到所有入度为 0的顶点(没有依赖的顶点)
  2. 将它们加入结果序列
  3. 从图中删除这些顶点和它们的边
  4. 重复步骤 1-3,直到所有顶点都被处理

如果最终结果包含所有顶点,则排序成功;如果还有剩余顶点,说明图中有环。

2.2 图解过程

假设有如下图:

5 → 0 ← 4 ↓ ↓ 2 → 3 → 1

步骤 1:找到入度为 0 的顶点:5, 4

  • 结果序列:[5, 4]

步骤 2:删除 5 和 4 的出边,更新入度

  • 顶点 0 的入度从 2 变为 0
  • 顶点 2 的入度从 1 变为 0

步骤 3:找到入度为 0 的顶点:0, 2

  • 结果序列:[5, 4, 0, 2]

步骤 4:删除 0 和 2 的出边,更新入度

  • 顶点 1 的入度从 1 变为 0
  • 顶点 3 的入度从 1 变为 0

步骤 5:找到入度为 0 的顶点:1, 3

  • 结果序列:[5, 4, 0, 2, 1, 3]

2.3 代码实现

#include<iostream>#include<vector>#include<queue>usingnamespacestd;vector<int>topologicalSort(intn,vector<vector<int>>&edges){// 构建邻接表和入度数组vector<vector<int>>graph(n);vector<int>inDegree(n,0);for(auto&edge:edges){intfrom=edge[0];intto=edge[1];graph[from].push_back(to);inDegree[to]++;}// 将所有入度为 0 的顶点加入队列queue<int>q;for(inti=0;i<n;i++){if(inDegree[i]==0){q.push(i);}}vector<int>result;while(!q.empty()){intnode=q.front();q.pop();result.push_back(node);// 删除该顶点的所有出边for(intneighbor:graph[node]){inDegree[neighbor]--;// 如果入度变为 0,加入队列if(inDegree[neighbor]==0){q.push(neighbor);}}}// 检测是否有环if(result.size()!=n){return{};// 有环,返回空数组}returnresult;}intmain(){// 示例:课程依赖关系// 0: 数据结构, 1: 算法设计, 2: 操作系统// 3: 编译原理, 4: 高级算法vector<vector<int>>edges={{0,
http://www.zskr.cn/news/1417110.html

相关文章:

  • 避开次谐波振荡!深入浅出解析电流模式Buck的斜坡补偿与环路稳定
  • DLSS Swapper终极指南:一键切换游戏超采样版本,免费提升显卡性能
  • Navicat Mac版无限试用重置:3种终极解决方案告别14天限制
  • 【Claude私有化部署生死线】:从模型量化精度损失率、KV Cache内存膨胀系数到审计日志完整性验证——金融级落地必查清单
  • LAMMPS模拟石墨烯拉伸:除了velocity,试试这个更省事的deform命令(附完整in文件)
  • 从Excel到MATLAB:手把手教你处理实验数据并完成最小二乘拟合(避坑指南)
  • 告别双系统!在Win11上用WSL2搭建Ubuntu 18.04 + ROS Melodic开发环境(附网络问题终极解决方案)
  • PS 平面图制作立体感教程 4 种实用方法全解析
  • 保姆级教程:在博途V14中手把手配置S7-1500T与V90 PN的PROFINET通信(含HSP安装避坑)
  • 如何快速提升英雄联盟游戏效率:终极自动化工具完整指南
  • 咸阳本地热水器维修 全城就近上门质保一年 - GrowthUME
  • STM32 HAL库三LED九种模式闪烁项目实战:从GPIO原理到工程优化
  • 弯头厂家哪家好主流厂商横评:近两年核心差异(含行业FAQ - 速递信息
  • 基于OpenLIT实现三层 LLM Agent 可观测性的实践
  • 基于Arduino与红外传感器的DIY音乐盒:从传感器原理到嵌入式音乐合成
  • AI Agent 开发大比拼!2026年选型指南,Python仍是王者,TypeScript崛起,混合架构成主流!
  • 嵌入式Linux内存稳定性测试:手把手教你用memtester排查硬件‘暗病’(附RK3399实测)
  • Ka波段SIW接收机设计:实现立方星高速星间通信
  • 别再踩坑了!用mqtt.js连接MQTT时,WebSocket端口(8083/8084)和TCP端口(1883)到底怎么选?
  • Python3 注释
  • 大厂面试高频考点!手把手拆解AI Agent工具调用与Function Calling原理及工程实践
  • GRBL Plotter:从创意到现实的数控加工终极指南 [特殊字符]
  • 将Taotoken作为统一AI网关融入微服务架构
  • 用STM32F103C8T6和LD3320语音模块做个声控小台灯:GPIO电平读取的保姆级教程
  • H3C S10500/S7500E交换机密码恢复:保留原配置 vs. 彻底重置,两种方案怎么选?
  • 告别Visio和PPT!用Python的Plotly+Dash为数学建模打造动态交互式流程图
  • OpenVoiceV2核心技术完全解析:从架构原理到实战部署
  • 基于EVM预测的Massive MIMO自适应用户分组算法解析
  • PCB阻焊覆盖的唯一依据:Gerber文件
  • qmcdump:免费解锁QQ音乐加密文件,一键转换通用音频格式终极指南