tarjan算法的原理和实现

Tarjan算法的操作原理如下:

  1. 在任何深度优先搜索中,同一强连通分量内的所有顶点均在同一棵深度优先搜索树中。也就是说,强连通分量一定是有向图的某个深度搜树子树。
  2. 我们用low值记录该点所在强连通子图对应的搜索子树的根节点的Dfn值。注意,该子树中的元素在栈中一定是相邻的,且根节点在栈中一定位于所有子树元素的最下方。
  3. 强连通分量是由若干个环组成的。所以,当有环形成时(也就是搜索的下一个点已在栈中),我们将这一条路径的low值统一,即这条路径上的点属于同一个强连通分量。
  4. 如果遍历完整个搜索树后某个点的dfn值等于low值,则它是该搜索子树的根。这时,它以上(包括它自己)一直到栈顶的所有元素组成一个强连通分量。

low值和Dfn值各代表什么:

Dfn值代表在一次深度优先搜索中各节点所处的次序,如果一个图是强连通的,它必然是可以被一个环串起所有的点,反之则不然,所以叶子节点必然是存在的。

什么样的节点可以看成根节点:low[v]=Dfn[v]。这个根节点是强连通子图的根节点。

== 伪代码 ==
 '''algorithm''' tarjan '''is'''
   '''input:''' 图 ''G'' = (''V'', ''E'')
   '''output:''' 以所在的强连通分量划分的顶点集
 
   ''index'' := 0
   ''S'' := empty    ''// 置栈为空''
   '''for each''' ''v'' '''in''' ''V'' '''do'''
     '''if''' (''v''.index is undefined)
       strongconnect(''v'')
     '''end if'''
 
   '''function''' strongconnect(''v'')
     ''// 将未使用的最小index值作为结点v的index''
     ''v''.index := ''index''
     ''v''.lowlink := ''index''
     ''index'' := ''index'' + 1
     ''S''.push(''v'')
 
     ''// 考虑v的后继结点''
     '''for each''' (''v'', ''w'') '''in''' ''E'' '''do'''
       '''if''' (''w''.index is undefined) '''then'''
         ''// 后继结点w未访问,递归调用''
         strongconnect(''w'')
         ''v''.lowlink := min(''v''.lowlink, ''w''.lowlink)
       '''else if''' (''w'' is in ''S'') '''then'''
         ''// w已在栈S中,亦即在当前强连通分量中''
         ''v''.lowlink := min(''v''.lowlink, ''w''.index)
       '''end if'''
 
     ''// 若v是根则出栈,并求得一个强连通分量''
     '''if''' (''v''.lowlink = ''v''.index) '''then'''
       start a new strongly connected component
       '''repeat'''
         ''w'' := ''S''.pop()
         add ''w'' to current strongly connected component
       '''until''' (''w'' = ''v'')
       output the current strongly connected component
     '''end if'''
   '''end function'''

变量<tt>index</tt>是深度优先搜索的结点计数器。<tt>S</tt>是栈,初始为空,用于存储已经访问但未被判定属于任一强连通分量的结点。注意这并非一个一般深度优先搜索的栈,结点不是在以它为根的子树搜索完成后出栈,而是在整个强连通分量被找到时。

最外层循环用于查找未访问的结点,以保证所有结点最终都会被访问。<tt>strongconnect</tt>进行一次深度优先搜索,并找到结点<tt>v</tt>的后继结点构成的子图中所有的强连通分量。

当一个结点完成递归时,若它的<tt>lowlink</tt>仍等于<tt>index</tt>,那么它就是强连通分量的根。算法将在此结点之后入栈(包含此结点)且仍在栈中的结点出栈,并作为一个强连通分量输出。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章