拓扑排序讲解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拓扑排序讲解相关的知识,希望对你有一定的参考价值。

在这里我们要说的拓扑排序是有前提的

        我们在这里说的拓扑排序是基于有向无环图的!!!。

(⊙o⊙)…我所说的有向无环图都知道是什么东西吧。。

如果不知道,我们下面先来来说说什么是有向无环图。

所谓有向无环图,顾名思义是不存在环的有向图(至于有向图是什么不知道的在前面我们有一个图论讲解上都有)。

点的入度:以这个点为结束点的边数。

点的出度:以这个点为出发点的边的条数。

拓扑序就是对于一个节点的一个排列,使得(u,v)属于E,那么u一定出现在v的前面。然而拓扑排序就是一个用来求拓扑序的东西。

技术分享对于左面的这个图,一个合法的拓扑序是(1,2,4,3,5)。

 

又有一个问题了,知道了这些东西后,我们又要怎样求一个有向无环图的拓扑序呢?

我们可以观察到拓扑排序的定义是:若(u,v)∈E,那么u在排列中出现的位置一定在v前面。

也就是说,考虑一个节点u,当我们删除u在序列中处于他前面的所有点之后,u的入度应该是0.

因此,我们就得到了一个拓扑排序的大致的算法思路。

具体怎么着呢  ?。?

循环n次

    选定一个入度为0且仍存在(未出现在序列中)的点v

  删除点v以及从从点v出发的所有边,更新剩余点的入度

重复上述过程,这样我们就可以得到一个合法的拓扑序。

既然这样,我们就总结下拓扑排序的精髓吧。

精髓(具体方法):
⑴ 从图中选择一个入度为0的点加入拓扑序列。
⑵ 从图中删除该结点以及它的所有出边(即与之相邻点入度减1)。
反复执行这两个步骤,直到所有结点都已经进入拓扑序列。

还可不可以消化得了?

如果还不可以的话,下面我们就来具体讲一讲拓扑排序吧。

参考博客:http://blog.csdn.net/dm_vincent/article/details/7714519

一。定义

将有向图中的顶点以线性方式进行排序。即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点v的前面。

 

如果这个概念还略显抽象的话,那么不妨考虑一个非常非常经典的例子——选课。我想任何看过数据结构相关书籍的同学都知道它吧。假设我非常想学习一门机器学习的课程,但是在修这么课程之前,我们必须要学习一些基础课程,比如计算机科学概论,C语言程序设计,数据结构,算法等等。那么这个制定选修课程顺序的过程,实际上就是一个拓扑排序的过程,每门课程相当于有向图中的一个顶点,而连接顶点之间的有向边就是课程学习的先后关系。只不过这个过程不是那么复杂,从而很自然的在我们的大脑中完成了。将这个过程以算法的形式描述出来的结果,就是拓扑排序。

二。代码实现

#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
struct Edge
{
    int x,y,next;
    Edge(int x=0,int y=0,int next=0):
    x(x),y(y),next(next) {}
}edge[maxn];
int n,m,head[maxn],sumedge,inn[maxn];
int ins(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    return head[x]=sumedge;
}
int Head,tail,que[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
        inn[y]++;
    }
    Head=1;tail=0;
    for (int i=1;i<=n;i++)
     if (inn[i]==0) que[++tail]=i;//如果该点的入度为0,删掉与这个点相连的点,删后如果入度为0的话,把该点入队 .
    for (;Head<=tail;Head++)//循环枚举与该点相连的点,把该点入队。 
    {//循环上述过程,直到说有的点都入队(有向无环图,每一个点肯定都与一个点相连,这样我们重复这个过程,就可以很好地把所有的带点都考虑到,如此一来,所有的点就都入队了。 
        int x=que[Head];
        for (int u=head[x];u;u=edge[u].next)
        {
            inn[edge[u].y]--;//删掉与这个点相连的点
            if (inn[edge[u].y]==0)// 删后如果入度为0的话
             que[++tail]=edge[u].y;//把该点入队 
        }
    }
    return 0;
}

就说这些吧,我们在下面还会再说几个例题。(那就请看下一页吧)

以上是关于拓扑排序讲解的主要内容,如果未能解决你的问题,请参考以下文章

拓扑排序()

图解:有向环拓扑排序与Kosaraju算法

(王道408考研数据结构)第六章图-第四节6:拓扑排序(AOV网代码排序规则)

拓扑排序算法实现

拓扑排序代码:

使用 C# 代码实现拓扑排序