15-拓扑排序(Topological Sort)

在研究拓扑排序之前,先来了解一个概念。

AOV网(Activity On Vertex Network)

什么叫AOV网呢?在生活中经常有这种情况,一项大的工程,常常被分为多个小的子工程,然后小的子工程中之间可能存在一定的先后顺序,即某些子工程必须在其他一些子工程完成后才能开始。

在现代化管理中,人们常常用有向图来描述和分析一项工程的计划和实施过程,其中子工程被称为活动(Activity)

  • 顶点表示活动,有向边表示活动之间的先后关系,这样的图,简称AOV网

例如:下图就表示一个AOV网

图中的每一个顶点就代表一个子工程(Activity),有向边代表活动之间的先后顺序与依赖关系,例如箭头A→B,就表示需要先完成活动A才能开始活动B,所以B完成以后才能开始活动C和活动D,只有活动C,活动B,活动D都完成以后,才能开始活动E,活动E完成以后,才能开始活动F。所以上图AOV网中活动之间的依赖关系如下

  • B依赖于A
  • C依赖于B
  • D依赖于B
  • E依赖于B,C,D
  • F依赖于E

通过这个依赖关系,可以观察到,一个 顶点的依赖,是由该顶点的inEdges(入度)决定的。即有多少条边进入该顶点,如果该顶点有3条边进入,则说明该顶点有3个依赖

一个标准的AOV网需要满足的条件:必须是一个有向无环图(Directed Acyclic Graph,简称DAG)

拓扑排序(Topological Sort)

什么叫拓扑排序,首先结合下图来理解一些基本概念

  1. 前驱活动:有向边起点的活动称为终点的前驱活动;例如B称为C的前驱活动
    • 只有当一个活动的前驱全部完成后,这个活动才能进行;例如E只有当全部前驱B,C,D完成以后,才能进行
  2. 后继活动:有向边终点的活动称为起点的后继活动;例如E称为C的后继活动

什么叫拓扑排序?

  • 将AOV网中所有的活动,排成一个序列,使得每一个活动的前驱活动都排在该活动的前面;也就是说拓扑排序将所有的活动排好序后,根据这个顺序,恰好能将所有的活动都执行完

所以,上图的AOV网,如果要进行拓扑排序,最终排序的结果如下

  • A→B→C→D→E→F 或者
  • A→B→D→C→E→F

结果并不一定是唯一的。

那应该如何实现拓扑排序呢?

实现思路

实现拓扑排序,可以利用卡恩算法(Kahn与1962年提出)完成拓扑排序

  • 假设L是存放拓扑排序结果的列表
    1. 把所有入度为0的顶点放入L中,然后把这些顶点从图中去掉
    2. 重复操作1,直到找不到入度为0的顶点

根据这种思路,假设对下图进行拓扑排序

首先将度为0的顶点放入列表中

然后将这些顶点从图中删除,最终删除后的结果如下

基础将入度为0的顶点放入列表中

然后将A从图中删除,最终删除后的结果如下

继续将入度为0的顶点放入列表中

将B,D从图中删除,最终只剩下顶点F

现在F的入度为0,所以现在又将F放入列表中

最终,所有顶点都加入到了列表中,没有剩下入度为0的顶点,说明拓扑排序完成。另外如果列表中的元素个数与顶点的总数相同,也说明拓扑排序完成。

但是,如果已经找不到入度为0的顶点,但是列表中的元素个数少于顶点总数,则说明原图中存在环,无法进行拓扑排序。

由于卡恩算法的实现,是将度为0的顶点加入列表后,将这些顶点从图中删除,如果按照这种方法进行操作,会破坏原有的数据,所以在实现拓扑排序时,会结合卡恩算法进行适当的调整。步骤是这样的

  1. 首先创建一个List,用来存放排序后顶点的值
  2. 创建一个队列,用来存放当前入度为0的顶点
  3. 创建一个表,备份所有顶点入度
  4. 将当前入度为0的顶点入队
  5. 将队头顶点出队,遍历当前顶点的outEdges,然后将遍历到的顶点,将这些顶点的inEdges减一,如果此时发现有减为0的顶点,则将该顶点入队,直到将outEdges遍历完为止。并将出队顶点的值添加到List中
  6. 继续将队头元素出队,重复步骤5
  7. 直到将队列中的元素全部出队为止,就完成了拓扑排序。

根据上面的分析,最终转换为代码的结果如下

public List<V> toplogicalSort() {
    List<V> list = new ArrayList<>();
    Queue<Vertex<V,E>> queue = new LinkedList<>();
    Map<Vertex<V,E>,Integer> map = new HashMap<>();
    //将度为0的节点,都放入队列中
    vertices.forEach((V v,Vertex<V,E> vertex)->{
        if (vertex.inEdges.size() == 0) {
            queue.offer(vertex);
        } else {
            map.put(vertex,vertex.inEdges.size());
        }
    });
    while (!queue.isEmpty()) {
        Vertex<V,E> vertex = queue.poll();
        list.add(vertex.value);//将顶点的值,放入返回结果中
        for (Edge<V,E> edge: vertex.outEdges ) {
            int toIn = map.get(edge.to) - 1;
            if (toIn == 0) {
                queue.offer(edge.to);
            } else {
                map.put(edge.to,toIn);
            }
        }
    }
    return list;
}

demo下载地址

完!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容