算法 之 拓 扑 排 序
文章目录
- 拓扑排序,常用于这个课程表安排类型的,对于一个抽象为一个
有向无环图
,经过排序之后,排序之后的元素x,y
,仍然保持着在原来的有向无环图当中,x->y
,也就是前后的顺序仍然不变
灵神讲解
- 讲一下拓扑排序的思路:
- 首先输入的是一个边的关系
edges[i] = [x,y]
表示,存在x->y
的有向边,我们需要将这个边,使用邻接表存储起来,同时还使用一个数组存储每一个顶点的入度数量
- 使用一个队列来存储候选将要拓展的节点,当然一开始,加入队列的元素就是
入度为0的节点
- 选取队列中的元素,加入最终的排序的数组中,同时,对于以该元素作为起始节点的边所对应的节点的入度数量应该
-1
,同时判断,将新的入度数量为0的节点加入候选队列当中 - 如果最终,排序的元素数量少于总的节点数量,则说明存在环
- 首先输入的是一个边的关系
// 返回有向无环图(DAG)的其中一个拓扑序
// 如果图中有环,返回空列表
// 节点编号从 0 到 n-1
vector<int> topologicalSort(int n, vector<vector<int>>& edges) {vector<vector<int>> g(n);vector<int> in_deg(n);for (auto& e : edges) {int x = e[0], y = e[1];g[x].push_back(y);in_deg[y]++; // 统计 y 的先修课数量}queue<int> q;for (int i = 0; i < n; i++) {if (in_deg[i] == 0) { // 没有先修课,可以直接上q.push(i); // 加入学习队列}}vector<int> topo_order;while (!q.empty()) {int x = q.front();q.pop();topo_order.push_back(x);for (int y : g[x]) {in_deg[y]--; // 修完 x 后,y 的先修课数量减一if (in_deg[y] == 0) { // y 的先修课全部上完q.push(y); // 加入学习队列}}}if (topo_order.size() < n) { // 图中有环return {};}return topo_order;
}