zoukankan      html  css  js  c++  java
  • 拓扑排序

    拓扑排序在百度百科中的解释是:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。

    转换为显示中比较容易理解的例子就是,在大学有学过课程需要学习,例如要想学习数据结构,首先就需要学习完C语言才可以,那么我们就可以将课程看成图中的点,将先学习c语言再学习数据结构看成是一条C语言指向数据结构的有向边。那么我们只需要找到一个线性的排列顺序,使得这个顺序满足所有的课程的前置要求(就是要想学习这门课程,需要将该课程的所有前置课程学完)。那么我们也比较容易的知道,拓扑排序并不一定是一个唯一的线性顺序。

    在学习拓扑排序的算法之前,我们需要先了解几个基本概念

    出度:以点u为起点的边的数量是u的出度

    入度:以点u为终点的边的数量是u的入度

    对于拓扑排序而言有BFS和DFS两种算法


    BFS

    基于BFS的拓扑排序也可以分为两类:无前驱的顶点优先、无后继的顶点优先

    无前驱的顶点优先拓扑排序

    1:预处理,遍历每个边,计算出所有顶点的出度和入度。复杂度O(V+E),其中包含每个顶点的初始化

    2:找到所有入度为0的顶点,放进队列,作为起点(这些点的先后顺序无所谓)。如果找不到入度为0的点,那么这个图不是DAG,不存在拓扑排序

    3:弹出队首元素,将队首的所有直接邻居点(队首元素指向的邻居节点)的入度减一,把入度变为0的结点放入队列。

    4:重复操作3,直到队列为空。这个时候队列的所有弹出顺序就是一个拓扑排序。

    拓扑排序无解的判定条件:如果队列为空时,仍旧有点没有进入过队列,那么这些点的入度都不可能为0,一定存在一个有向环

    无后继的顶点优先拓扑排序

    相当于是无前驱的反向执行

    1:预处理,计算出所有顶点的出度和入度

    2:找到所有出度为0的顶点,放入队列。如果找不到,则不存在拓扑排序

    3:弹出队首元素,将队首的所有直接邻居结点(指向对手的邻居节点)的出度减一,把出度为0的结点放入队列

    4:重复操作3,直到队列为空。这个时候队列的弹出顺序的逆序就是一个拓扑排序。

    总的来说,BFS的复杂度是O(V+E)

    DFS

    只需要在传统的dfs中加入一个对点的处理就是一个拓扑排序算法

    对于dfs的拓扑排序,最好是加一个虚拟结点0,再加n条边有向边,为0指向所有n个结点的有向边。这个时候只要从虚拟结点0进行dfs遍历就可以了,这样避免了图不联通的情况下,需要用循环dfs了。

    dfs实际是递归,递归包含递推和回归,在回归的时候输出拓扑排序,但是注意这个时候的拓扑排序是逆序,所以可以使用栈来暂时存储,最后用栈输出就可以解决了。

    要求字典序最小或者最大的拓扑排序。使用优先队列的正向拓扑排序解决

    要求1尽可能在最前面,在1的前提下,让2尽可能在前面,在1和2的前提下,让3尽可能在前面,如此类推。使用优先队列并且是逆向拓扑排序

    写于:2020/8/19 15:57

    修改于:2020/8/19 21:17


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    前端js部分面试题
    前端css部分面试笔试题
    javascript 面向对象
    string 对象
    JavaScript 正则表达式
    JavaScirpt 位运算
    JavaScript冒泡循环排序案例
    JavaScript 练习题
    浏览器缓存机制
    浏览器对象模型(BOM)
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13529846.html
Copyright © 2011-2022 走看看