[图 | C实现] 拓扑排序 | 拓扑有序序列 | 有向图是否有回路

背景

用【有向图】表示一个【工程的施工图】或【程序的数据流图】,则图中不允许出现回路

例子:
【回路】 打地基->做房子结构->砌墙->装修->打地基
【解释】 “做房子结构“的前提是“打地基”,“砌墙”的前提是“做房子结构”,“装修”的前提是“砌墙”,“打地基”的前提是“装修”
【说明】 到底是哪一个先开始,有回路就没法做了

拓扑排序

如何检查【有向图】中是否存在【回路】的方法之一:
对【有向图】进行【拓扑排序】

拓扑排序是什么

按照【有向图】给出的【次序关系】,将图中【顶点】排成一个【线性序列】,对于【有向图】中没有限定次序关系的顶点,则可以人为加上任意的次序关系
这样得到的【线性序列】称为【拓扑有序序列】
【拓扑排序】的目标呢:就是构造一个【拓扑有序序列】

如何进行拓扑排序

  1. 从【有向图】中选取一个没有前驱的顶点,并输出=>选【入度为0的顶点】
  2. 从有向图中删去【此顶点】以及所有【以它为尾的弧】=>弧头顶点的入度减1
  3. 重复以上两步,直至【图空】,或者【图不空但找不到无前驱的顶点】为止

举例

例一

这里写图片描述

步骤数 入度为0的有 选择顶点
并删除顶点与弧
输出
1 A,B,C A “A”
2 B,C B “AB”
3 D,C D “ABD”
4 F,G,C F “ABDF”
5 G,C G “ABDFG”
6 C C “ABDFGC”
7 E E “ABDFGCE”
8 H H “ABDFGCEH”
9 I I “ABDFGCEHI”

图空,没有回路,”ABDFGCEHI”为【拓扑有序序列】

例二

这里写图片描述

步骤数 入度为0的有 选择顶点
并删除顶点与弧
输出
1 A,C A “A”
2 C C “AC”

找不到入度为0的顶点=>退出=>图还没有空图=>有回路

定量分析

思路

取入度为0的顶点v;
while (v<>0) {
    printf(v); ++m;
    // 所有入度减1
    w:=FirstAdj(v);
    while (w<>0) {
        inDegree[w]--;
        w:=nextAdj(v,w);
    }
    取下一个入度为0的顶点v
}
if m<n  printf("图中有回路")

优化

为避免每次都要搜索【入度为0的顶点】
在算法中设置一个“栈”,以保存“入度为0”的顶点

CountInDegree(G, indegree); //对各个顶点求入度
InitStack(S);
for (i=0; i<G.vexnum; ++i) {
    if (!indegree[i]) Push(S,i); //入度为0的顶点入栈
}
count = 0; //对输出顶点计数
while (!EmptyStack(S)) {
    Pop(S,v); ++count; printf(v);
    for (w=FirstAdj(v); w; w=NextAdj(G,v,w)) {
        --indegree(w);
    }
    //新产生的入度为零的顶点入栈
    if (!indegree[w]) Push(S,w);
}
if (count<G.vexnum) printf("图中有回路")

猜你喜欢

转载自blog.csdn.net/summer_dew/article/details/81604206
今日推荐