其他分享
首页 > 其他分享> > 最强连通分量(Tarjan)笔记

最强连通分量(Tarjan)笔记

作者:互联网

引言

在静态分析技术中, 我们常用会将代码转成抽象语法树(AST), 然后采用深度遍历(DFS)来完成对语法树的遍历和查询,找到潜在的问题缺陷。

对于语义的分析,我们采用的控制流和数据流也都无一例外的采用了以图为基础的算法, 通过图的可达性, 来完成变量、表达式的可达分析, 以及变量的依赖分析、值流图等等。

图的算法是进行静态分析的基础数据算法,如何提高图的分析效率,就需要对图的算法有进一步的认识。

Tarjan算法

图的一些基本概念:

求强连通分量就是我们今天要解决的问题,根据强连通分量定义,用双向遍历取交集的方法求强连通分量,时间复杂度为 \(\Theta(N^2+M)\). 而Tarjan或Kosaraju算法, 两者的时间复杂度都是 \(\Theta(N+M)\)。

算法简介

Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

由于在这个过程中每个点只被访问一次,每条边也只被访问一次,所以Tarjan算法的时间复杂度是 \(\Theta(n + m)\).

tarjan(u) {
    DFN[u] = LOW[u] = ++Index            //为节点u设定次序编号和Low初值
    Stack.push(u)                        //将节点u压入栈中
    for each(u, v) in E                  //枚举每一条边 
        if(v is not visted)              //如果节点v未被访问过 
            tarjan(v)                    //继续向下找 
            LOW[u] = min(LOW[u], LOW[v]) //
        else if(v in Stack)              //如果节点v还在栈内 
            LOW[u] = min(LOW[u], DFN[v]) //
    if(DFN[u] == LOW[u])                 //如果节点u是强连通分量的根 
        repeat                           //循环出栈,直到u=v 
            v = Stack.pop                //将v退栈,为该强连通分量中的一个顶点 
            print v                      //输出v 
        until(u == v)                    //循环终止条件u=v 
}

举例演算

0.求下面有向图的强连通分量

image

1.从节点0开始DFS:

image

2.返回节点4:

3.返回节点2:

4.从节点2继续搜索到节点3:

5.返回节点2;

6.返回节点0;

7.从节点0继续搜索到节点1;

8.返回节点0;

结论

参考

参考史上最清晰的Tarjan算法详解

标签:Tarjan,min,连通,笔记,DFN,LOW,节点,分量
来源: https://www.cnblogs.com/sunskydp/p/tarjan-note.html