史上最清晰的Tarjan算法详解
【摘要】 1. 引言在静态分析技术中, 我们常用会将代码转成抽象语法树(AST), 然后采用深度遍历(DFS)来完成对语法树的遍历和查询,找到潜在的问题缺陷。 对于语义的分析,我们采用的控制流和数据流也都无一例外的采用了以图为基础的算法, 通过图的可达性, 来完成变量、表达式的可达分析, 以及变量的依赖分析、值流图等等。 图的算法是进行静态分析的基础数据算法,如何提高图的分析效率,就需要对图的算法有进...
1. 引言
在静态分析技术中, 我们常用会将代码转成抽象语法树(AST), 然后采用深度遍历(DFS)来完成对语法树的遍历和查询,找到潜在的问题缺陷。 对于语义的分析,我们采用的控制流和数据流也都无一例外的采用了以图为基础的算法, 通过图的可达性, 来完成变量、表达式的可达分析, 以及变量的依赖分析、值流图等等。 图的算法是进行静态分析的基础数据算法,如何提高图的分析效率,就需要对图的算法有进一步的认识。
1.1. 故事从1986年的图灵奖说起
1986年的图灵奖是John E.Hoperoft和Robert E·Tarjan两人共同获得, 而且Robert E·Tarjan曾是John E.Hoperoft的学生,他们的密切合作取得了算法设计与分析方面的卓越贡献, 赢得了1986年度美国计算机协会(Association for Computing Machinery, ACM)图灵奖的荣誉。
John E. Hopcroft |
Robert Endre Tarjan |
1.2. 故事的前半段
在领奖的时候,John E.Hopcroft 做了一个“计算机科学:一门学科的出现” 的演讲, 从他自己的经历出发,展现了计算科学在那个风起云涌的年代形成的过程。
时间回到1964年,计算机才刚刚成为一门学科, 普林斯顿大学一个偶然的邀请,使本打算到美国西海岸教授电器工程的Hoperoft改变了自己的人生轨迹,从此投入到了计算机科学的研究。
那个时候,计算机科学的大部分课程的内容都是围绕着数字计算机电路的设计以及如何减少构造这些电路所需要的晶体管数展开的。然而, 到了六十年代中期, 技术的进步已使得晶体管马上就要被每片有多达几百个元件的计算机芯片所取代。因此, 减少晶体管数再没有么意义,那时所谓的计算机科学的课程即将过时, 必须发展新的课程。
Hopcroft 并没有接受过正规计算机教育,只是他在斯坦福大学读电器工程学博士的时候,上过David Huffman(霍夫曼编码的发明者)教的一门计算机课程,学习了开关电路、逻辑设计以及计算理论的基本知识。普林斯顿要Hoperoft在自动机理论方面开设一门新的课程,当时没有任何教程可以参考, 只给了他推荐了6篇论文。 其中包括:
- 1943年,McCulloch和Pitts发表的一篇关于用来描述神经网络中活动的逻辑演算的论文。这些活动是一系列的电脉冲, 并能看作是0-1串。论文提出了一种描述神经网中的0-1串是如何结合以产生新的0-1串的方法。这种描述方法后来被发展成为一种描述串集的正则表达式语言。
- 数学家Michael Rabin和Dana Scott提出的一种具有有限量存储其的计算机模型,这个模型就是有限状态自动机。并证明了有限状态自动机的可能的行为和正则表达式所描述的行为的一致性。 数学和计算机学思想的汇集,使计算机科学家相信正则语言和有限自动机的重要性。
- 语言学家Chomsky研究发展的一种前后文无关文法的概念。这与Backus和Naur为描述各种程序设计语言的语法而发展的一套形式表示法惊人的等价。
- 图灵于1963年引入了一种简单的计算装置模型,现在称做图灵机。并论证了能够进行的任何计算过程都能在图灵机上编程序实现。图灵机是现代可计算理论的基础。
- 数学家Hartmanis和Stearns采用算法的执行步数来度量算法的复杂性,并使这一方法发展了一种复杂性分类的理论。
1967年,Hopcroft转去康奈尔大学,转而研究算法与数据结构。他相信理论计算机科学的方法学,可以用来为算法设计发展一种科学基础,这对于实践者将是很有用的。
在七十年代初期, Hopcroft在斯坦福大学度过了一年的假期, 在那里遇到Robert Tarjan并与他同用一间办公室, Tarjan那时是二年级研究生。获得这次图灵奖的研究就是在那段合作时间里作的。
Hopcroft 在发言的最后,还不忘呼吁,为了保持美国取得的技术和经济的领导地位,必须对计算机科学进行全国性的投入和支持。
1.3. 故事的后半段
说到Tarjan,他在图论算法和数据结构领域有很大的贡献。 下面对这个大牛也做个简单的介绍。
Tarjan在1969年获得了加州理工学院数学学士学位。在斯坦福大学,他获得了他的计算机科学硕士学位(1971)和博士学位(1972). Tarjan从1985年开始任教于普林斯顿大学。
Tarjan还拥有很多研究所和公司的工作经验, 例如:AT&T贝尔实验室、NEC研究所、InterTrust Technologies、康柏、惠普、微软等。
Tarjan是一个非常高产的计算机科学家,从计算机科学出版物在线参考网站dblp收集的有关他发表在的杂志、会议和出版物,多达300+。
他独立研究的算法有:Tarjan离线的LCA算法(一种优秀的求最近公共祖先的线性离线算法)、Tarjan强连通分量算法(甚至比后来才发表的Kosaraju算法平均要快30%)、Hopcroft-Tarjan算法(第一个平面性测试的线性算法)。
他还开发了一些重要的数据结构,比如斐波那契堆(Fibonacci Heap,插入查询合并O(1),删除O(logn)的强大数据结构)、伸展树(Splay Tree,和另外一位计算机科学家共同发明)、动态树(Link-Cut Tree,发明人之一)。
下图是他普林斯顿大学个人简介中的一个插图, 这个是他的另一个重要的研究领域:自适应搜索树的查询(self-adjusting search tree),在树的遍历过程中,改变树的结构以提高树的搜索效率。
他的主要荣誉:
- 1986年,与John Hopcroft分享了当年的图灵奖,原因是对算法和数据结构的设计分析做出的地基式的贡献;
- 1994年,被选为美国计算机协会(Association for Computing Machinery, ACM)院士;
- 2004年,欧洲科学院的Blaise Pascal数学和计算机科学奖章;
- 1983年,Rolf Nevanlinna奖的第一个获奖者,国际数学联盟在信息科学的数学方面的杰出贡献而每四年获奖一次;
2. Tarjan算法
图的一些基本概念:
- 关联(incident):点为边的端点;
- 邻接(adjacent):点与点关联同一条边,或边与边关联同一顶点;
- 子图:图G'的点和边都是图G的子集,则G'为G的子图;
- 道路:从点v到点u的路径;
- 简单道路:没有重复边的道路;
- 回路:起点与终点相同的道路;
- 简单回路:没有重复边的回路;
- 连通:两顶点间有道路;
- 强连通:有向图u→v与v→u都有道路;
- 连通图:任意两顶点间都有道路(若有向图除去方向后连通,则称有向图连通);
- 简单图:没有重复边和自环的图;
- 完全图:任意两顶点间有一条边到达的简单图(有向完全图与无向完全图);
- 强连通(strongly connected): 在有向图G 中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected);
- 强连通图: 如果有向图G 的每两个顶点都强连通,称G 是一个强连通图;
- 强连通分量(strongly connected components): 非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
求强连通分量就是我们今天要解决的问题,根据强连通分量定义,用双向遍历取交集的方法求强连通分量,时间复杂度为O($N^2$+M). 而Tarjan或Kosaraju算法, 两者的时间复杂度都是O(N+M)。
2.1. 算法简介
Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
-
定义:
- DFN(u)为节点u 搜索的次序编号(时间戳);
- LOW(u)为u 或 u的子树能够追溯到的最早的栈中节点的次序号;
由定义可以得出,当 DFN(u)=LOW(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
-
算法:
-
当首次搜索到点u时DFN[u]=LOW[u]=time;
-
每当搜索到一个点,把该点压入栈顶;
-
当u和v有边相连时:
- 如果v不在栈中(树枝边),DFS(v),并且LOW[u] = min{LOW(u),LOW(v)};
- 如果v在栈中(前向边/后向边),此时LOW[u] = min{LOW[u],DFN[v]}
-
当DFN[u]=LOW[u]时,将它以及在它之上的元素弹出栈,此时,弹出栈的结点构成一个强连通分量;
-
继续搜索,知道图被遍历完毕。
由于在这个过程中每个点只被访问一次,每条边也只被访问一次,所以Tarjan算法的时间复杂度是O(n+m).
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)