拓扑排序
636 字
3 分钟
拓扑排序
基本概念
AOV网
- 定义:在有向图中,顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行
- 特性:必须是有向无环图
拓扑排序
定义
将有向无环图中的所有结点排序,使得排在前面的结点不能依赖于排在后面的结点。
核心思想
不断选择图中入度为0的顶点输出,并删除该顶点及其所有出边。
算法流程
- 初始化: · 计算所有顶点的入度 · 将所有入度为 0 的顶点加入队列
- 循环处理: · 从队列中取出队头元素并输出 · 删除该顶点的所有出边(即后继顶点入度减1) · 如果某个后继顶点的入度变为 0,将其加入队列
- 结束条件: · 队列为空
环检测
· 无环:所有顶点都进入过队列 · 有环:存在未进入队列的顶点(这些顶点形成了环)
代码实现
#include <iostream>#include <vector>#include <queue>using namespace std;
const int N = 100010;
vector<int> graph[N]; // 邻接表int inDegree[N]; // 入度数组int n, m; // 顶点数、边数
bool topologicalSort() { queue<int> q; vector<int> result;
// 1. 将所有入度为0的顶点加入队列 for (int i = 1; i <= n; i++) { if (inDegree[i] == 0) { q.push(i); } }
// 2. 处理队列中的顶点 while (!q.empty()) { int u = q.front(); q.pop(); result.push_back(u);
// 删除u的所有出边,更新后继顶点的入度 for (int v : graph[u]) { inDegree[v]--; if (inDegree[v] == 0) { q.push(v); } } }
// 3. 判断是否有环 if (result.size() == n) { // 输出拓扑序列 for (int node : result) { cout << node << " "; } cout << endl; return true; // 无环 } else { cout << "图中存在环!" << endl; return false; // 有环 }}
int main() { cin >> n >> m;
// 构建图和入度数组 for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); inDegree[v]++; }
topologicalSort();
return 0;}关键要点
时间复杂度
- O(n + m):每个顶点和边各处理一次
应用场景
- 课程安排:先修课程关系
- 任务调度:依赖任务执行顺序
- 编译顺序:源文件依赖关系
- 工作流:工序先后关系
注意事项
- 拓扑序列不唯一:同一DAG可能有多个合法的拓扑序列
- 必须是有向图:无向图无法定义先后关系
- 必须无环:有环图无法进行拓扑排序
环检测应用
// 判断有向图是否有环bool hasCycle() { return !topologicalSort();}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
最小生成树
算法最小生成树:在连通带权无向图中,找到一个边权和最小的生成树
2
图的基本概念
算法定义:图中的边有方向性,用箭头表示。 表示:边 (A, B) 与 (B, A) 是两条不同的边。
3
单源最短路
算法每次从未确定最短路径的点中,选择距离起点最近的点,标记它的最短路径,并用它来更新邻居节点的距离。
4
算法错题本
算法在一个圆形操场的四周摆放 $N$ 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 $2$ 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
5
数论
算法如果 $a$ 除以 $b$ 没有余数,那么 $a$ 就是 $b$ 的倍数,$b$ 就是 $a$ 的约数,记作 $b \mid a$。 约数,也称因数。
随机文章随机推荐

