C++实现拓扑排序算法 _ 入度统计与广度优先搜索【详解】

老伟大大_4085

老伟大大_4085

2026-04-12

262人浏览

原创

kahn算法是c++中稳定、可检测环的拓扑排序实现,需先统计入度并用bfs:初始化时将入度为0的节点入队,每次取队首节点加入结果并更新邻接点入度,若最终序列长度小于节点数则存在环。

c++实现拓扑排序算法 _ 入度统计与广度优先搜索【详解】

拓扑排序在 C++ 中不能只靠 DFS 递归模拟来“假装跑通”——入度统计 + BFS(Kahn 算法)才是生产环境真正稳定、可检测环、易调试的实现方式。

为什么必须先统计每个节点的入度

入度为 0 是启动拓扑排序的唯一合法起点。不显式维护 indegree 数组,就无法在 O(1) 时间内判断哪个节点当前可加入队列;DFS 版本隐式依赖调用栈和回溯标记,一旦图含环或数据规模大,极易栈溢出或漏判。

实操建议:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 用 vector<int></int> 存储每个节点的入度,下标即节点编号(假设节点编号为 0 ~ n-1)
  • 建图时每添加一条边 u → v,立刻执行 indegree[v]++
  • 初始化队列前,遍历所有节点,把 indegree[i] == 0 的 i 入队
  • 别用 map 或 unordered_map 存入度——除非节点编号稀疏且极大,否则纯属增加常数开销和哈希冲突风险

用 queue 实现 BFS 拓扑排序的核心逻辑

这是 Kahn 算法的骨架,关键在于“删边”动作必须同步更新入度,并检查新产生的入度为 0 的节点。

常见错误现象:queue 为空但结果序列长度小于节点总数 → 图中存在环,应提前返回失败。

实操建议:

  • 使用 queue<int></int>(非 priority_queue),除非你明确需要字典序最小的拓扑序
  • 每次从队首取节点 u,将其加入结果 topo 向量
  • 遍历 graph[u] 中所有邻接点 v,执行 indegree[v]--;若此时 indegree[v] == 0,立即将 v 入队
  • 循环结束后检查 topo.size() == n,不等则说明有环,返回空 vector

邻接表怎么建才不踩内存与性能坑

邻接表是图的标准表示,但 C++ 中容易因类型或初始化方式引入越界、重复 push 或缓存不友好问题。

使用场景:适用于大多数稀疏有向图(边数远小于节点数平方)

实操建议:

  • 统一用 vector<vector>></vector>,而非 vector<list>></list> —— vector 连续内存,遍历时 CPU 缓存命中率高
  • 构造时预分配容量:graph.resize(n); for (int i = 0; i (按平均出度预估)
  • 加边函数写成内联或直接展开,避免函数调用开销:graph[u].push_back(v);
  • 不要在 BFS 过程中修改 graph 结构(如 erase)——只需改入度,图结构只读即可

完整可运行片段(无环检测版本)

下面是最小可用代码,去掉了异常处理和输入解析,聚焦核心逻辑:

vector<int> topo_sort(int n, const vector<vector>>& edges) {
    vector<vector>> graph(n);
    vector<int> indegree(n, 0);

    for (const auto& e : edges) {
        int u = e[0], v = e[1];
        graph[u].push_back(v);
        indegree[v]++;
    }

    queue<int> q;
    for (int i = 0; i  topo;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        topo.push_back(u);
        for (int v : graph[u]) {
            indegree[v]--;
            if (indegree[v] == 0) q.push(v);
        }
    }

    return topo.size() == n ? topo : vector<int>(); // 返回空表示有环
}
</int></int></int></vector></vector></int>

注意:实际项目中,节点编号可能不连续或从 1 开始,这时需做映射或调整 indegree 和 graph 大小;而环检测逻辑一旦被省略,后续依赖该序列的流程(如任务调度)就会静默失败——这点比算法本身更值得盯紧。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++ 排序算法

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6459

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

3145

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

4048

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2785

10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5907

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2528

6

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

2025.09.05

590

5

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.16

343

7

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.17

513

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习