拓扑排序详解

拓扑排序看起来很难,其实了解后不算难(思想非常清楚)

关键掌握思想后需要学会应用到具体的题目中去。(从入度为0到出度为0)

1、拓扑排序的介绍
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
    拓扑排序对应施工的流程图具有特别重要的作用,它可以决定哪些子工程必须要先执行,哪些子工程要在某些工程执行后才可以执行。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
    一个AOV网应该是一个有向无环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行(对于数据流来说就是死循环)。在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。
 
2、拓扑排序的实现步骤
在有向图中选一个没有前驱的顶点并且输出
从图中删除该顶点和所有以它为尾的弧(白话就是:删除所有和它有关的边)
重复上述两步,直至所有顶点输出,或者当前图中不存在无前驱的顶点为止,后者代表我们的有向图是有环的,因此,也可以通过拓扑排序来判断一个图是否有环。
 

3、拓扑排序示例手动实现
在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。
先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。
一直做改操作,直到所有的节点都被分离出来。
如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
下面是算法的演示过程。

4.实现代码(队列):O(V+E)
    queue<int>q;

    vector<int>edge[n];//这里使用了数组的vector数组来表示连接关系,实际上结构体也可以完成此任务

    for(int i=0;i<n;i++)  //n  节点的总数

        if(in[i]==0) q.push(i);  //将入度为0的点入队列

    vector<int>ans;   //ans 为拓扑序列(其实队列也可以完成)

    while(!q.empty())

    {

        int p=q.front(); q.pop(); // 选一个入度为0的点,出队列

        ans.push_back(p);

        for(int i=0;i<edge[p].size();i++)

        {

            int y=edge[p][i];    //y表示的是点p的直接后继结点

            in[y]--;    //入度减1

            if(in[y]==0)    //入度为0的点则需要入队

                q.push(y);  

        }

    }

    if(ans.size()==n)   

    {

        for(int i=0;i<ans.size();i++)

            printf( "%d ",ans[i] );

        printf("
");

    }

    else printf("No Answer!
");   //  ans 中的长度与n不相等,就说明无拓扑序列
        

————————————————
参考来源:
https://blog.csdn.net/qq_35644234/article/details/60578189
https://blog.csdn.net/qq_41713256/article/details/80805338
原文地址:https://www.cnblogs.com/xwh-blogs/p/12596250.html