Tarjan的算法:时间复杂性和轻微修改的可能性

时间:2014-06-09 05:29:53

标签: algorithm graph pseudocode tarjans-algorithm

此问题与one recently asked here相关但不相同。

我刚读过Wikipedia psuedocode

algorithm tarjan is
  input: graph G = (V, E)
  output: set of strongly connected components (sets of vertices)

  index := 0
  S := empty
  for each v in V do
    if (v.index is undefined) then
      strongconnect(v)
    end if
  end for

  function strongconnect(v)
    // Set the depth index for v to the smallest unused index
    v.index := index
    v.lowlink := index
    index := index + 1
    S.push(v)

    // Consider successors of v
    for each (v, w) in E do
      if (w.index is undefined) then
        // Successor w has not yet been visited; recurse on it
        strongconnect(w)
        v.lowlink  := min(v.lowlink, w.lowlink)
      else if (w is in S) then
        // Successor w is in stack S and hence in the current SCC
        v.lowlink  := min(v.lowlink, w.index)
      end if
    end for

    // If v is a root node, pop the stack and generate an SCC
    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

我显然一定不能理解它,因为我有两个非常基本的问题:

  1. 当我们说if (w is in S)时,那么O(N)或至少O(logN)复杂度的操作是不是因为元素应按其索引排序?我们必须为可从根节点访问的每个新节点执行此操作,因此不是总体复杂度O(NlogN)。此外,S是堆栈,因此从概念上讲,只有顶级元素应该是可访问的,我们如何在其中实现搜索?二元搜索树不应该是更好的数据结构吗?

  2. 在这部分:

    否则如果(w在S中)则为     v.lowlink:= min(v.lowlink,w.index)

  3. 是否有使用w.index而非w.lowlink的具体原因?使用w.lowlink的好处是它会回答上一个问题(链接的问题)。对于所有节点,SCC中所有节点的LLs将保证相同。

3 个答案:

答案 0 :(得分:4)

1)你的第一个问题:它很容易在O(1)中完成,只需维护一个布尔数组inStack,当时节点n放入堆栈,标记为{{1}到真的。当您将其从堆栈中弹出时,将其标记为false。

2)inStack[n]w.index之间没有太大区别,但这更容易理解,因为我们将理解这个条件是从节点A检查案例 - > B - &gt ; C - > A,检查节点C何时可以到达前任节点A.请记住,在我们更新C时,节点A lowlink尚未正确更新。

Tarjan算法基于以下事实:节点将成为SCC的根,当且仅当来自该节点时,我们无法到达任何前任节点(这意味着它在其SCC中具有最低的低链路并且也等于这个节点的索引)。所以条件只是以最直接的方式实现了这个想法,如果我们遇到一个已经访问过的节点,我们检查这个节点是否是当前节点的前身(由其索引确定,也是该级别)图中的这个节点)

答案 1 :(得分:1)

实际上我找到了一种方法来检查w是否在恒定时间内进入S.只需要一个布尔字段inStack

在堆栈中推送节点w时,设置w.inStack = true并弹出它,将其设为false。

但第二个问题仍然存在。我们可以在不干扰算法的情况下进行轻微修改吗?

答案 2 :(得分:0)

  1. 对于第二个问题,'我们可以进行轻微修改',我的 你猜是可以的。对于lowlink值,是指示节点, 谁没有更多未访问过的邻居,并且有dfs index = lowlink它是组件的根,因此可以弹出 堆叠和打印。

    因此,组件节点,lowlink值可以设置为任何值 大于或等于组件root的dfs索引。