[算法] 拓扑排序

10 篇文章 0 订阅

定义

对一个有向无环图(Directed Acyclic Graph,DAG)G进行拓扑排序,使得2任意一对定点 u u v,若边 (uv)E(G) ( u , v ) ∈ E ( G ) ,则在线性序列中 u u 出现在v之前。如下图所示的DAG:
这里写图片描述
一种可能的拓扑排序是:2->8->0->3->7->1->5->6->9->4->11->10->12。

分析

  • 从有向图中选择一个没有前驱(即入度为0)的定点并输出它;
  • 从图中删除该顶点,并且删除从该顶点出发的所有有向边;
  • 重复上述两步,直到剩余的图中所有节点都没有前驱为止。

拓扑排序得到的结果并不唯一

代码实现

假设有向无环图中有 n n 个节点,可以借助二维数组graph[n][n](邻接矩阵)来表示该图, graph[i][j] g r a p h [ i ] [ j ] 值为1则表示有从 i i 节点到j节点的有向边,用一维数组 indegree[n] i n d e g r e e [ n ] 表示该图所有节点的入度,将 graph g r a p h 中第 j j 列的所有2相加即得到indegree[j](即第 j j <script type="math/tex" id="MathJax-Element-868">j</script>个节点的入度),借助队列先进先出的特点来缓存入度为0的节点。代码实现如TopologicalSort.hpp所示:

#ifndef TopologicalSort_hpp
#define TopologicalSort_hpp

#include <queue>
#include <stdio.h>

void topologicalSort(int[][] graph, int nodeCnt, int result) {
    int[] indegree = new int[nodeCnt]; // 用于保存各节点入度
    queue<int> q; // 用来缓存入度为0的节点
    int cur; // 当前从队列头部取出的节点
    int cnt = 0;
    int i;

    // 计算各节点入度
    for (i = 0; i < nodeCnt; i++) { // 第i列
        for (int j = 0; j < nodeCnt; j++) { // 第j行
            indegree[i] += graph[j][i];
        }
    }

    // 缓存初始入度为0的节点
    for (i = 0; i < nodeCnt; i++) {
        if (indegree[i] == 0) {
            q.psuh(i);
        }
    }

    while (!q.empty()) {
        cur = q.front();
        q.pop();
        result[cnt++] = cur; // 保存当前元素到结果中
        for (i = 0; i < nodeCnt; i++) {
            if (graph[cur][i] != 0) {
                // 删除从cur出发的所有边,即相邻节点的入度减1
                if (--indegree[i] == 0) {
                    q.push[i];
                }
            }
        }
    }
}

#endif /* TopologicalSort_hpp */

总结

  • 拓扑排序的本质是不断输出入度为0的节点;
  • 拓扑排序可以用来判断一个有向图中是否存在环,若拓扑排序后得到的结果节点数量少于原图中节点数量,则有向图中存在环;
  • 拓扑排序其实是给定了节点的一组偏序关系;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值