将递归Tarjan转换为迭代以查找SCC

时间:2019-06-16 00:51:26

标签: c# algorithm recursion tarjans-algorithm

所以我已经成功实现了递归tarjan,它为我提供了图的SCC

我的递归实现如下:

public void DFSRecursive(long currentNode){
    low[currentNode] = preCount++;
    visited[currentNode] = true;
    stack.Push(currentNode);                                                                                                                 
    long minimum = low[currentNode];    
    foreach(long successorNode in SuccessorMap[currentNode])
    {
        if(!visited[successorNode])
        {
            DFSRecursive(successorNode);                 
        }
        if(low[successorNode] < minimum)
        {
        minimum = low[successorNode];
        }
    }
    if(minimum < low[currentNode])
    {
        low[currentNode] = minimum;
        return;
    }
    List<long> component = new List<long>();
    long stackTop;
    do
    {
        stackTop = stack.Pop();
        component.Add(stackTop);
    } 
    while(stackTop != currentNode);
    SCComponent.Add(component);
}

现在,我需要将其转换为迭代解决方案。我已经检查了很多资源来帮助我,其中包括一个非常类似的SO问题(Non-recursive version of Tarjan's algorithm)。我不能使用枚举器,因为我必须处理长值,并且当前状态的后继索引已存储在Dictionary(SuccessorMap [])中(需要处理节点数大于50亿的图)。

我已遵循将递归解决方案转换为迭代解决方案的一般准则:

  1. 通过推送到本地堆栈替换了递归调用
  2. 将“ returns”替换为本地堆栈中的pop
  3. 在循环开始时设置变量,并从本地弹出 堆栈

    public void DFSIterative(long currentNode)
    {
        var internalStack = new Stack<long>();
        low[currentNode] = preCount++;          
        stack.Push(currentNode);
        long minimum = low[currentNode];
        internalStack.Push(currentNode);
    
        while(!(internalStack.Count == 0))
        {
          currentNode = internalStack.Pop();
          visited[currentNode] = true;
          foreach(long successorNode in SuccessorMap[currentNode])
          {
            if(!visited[successorNode])
            {
              internalStack.Push(successorNode); 
            }
            if(low[successorNode] < minimum)
            { 
              minimum = low[successorNode];
            }
          }
          if(minimum < low[currentNode])
          {
            low[currentNode] = minimum;
            return;
          }
       }
       List<long> component = new List<long>();
       long stackTop;
       do
       {
         stackTop = stack.Pop();
     component.Add(w);
       }
       while(stackTop != currentNode);
    
       SCComponent.Add(component);
       }
    

我认识到迭代方法中的do-while循环将始终抛出InvalidOperationException(stack empty),但我还没有弄清楚迭代实现递归do-while的方法。

真的很感谢能帮助我的各种帮助。

0 个答案:

没有答案