代码之家  ›  专栏  ›  技术社区  ›  ChrisW

避免递归

  •  1
  • ChrisW  · 技术社区  · 15 年前

    我有一些代码在实现中使用递归。这个 profiler which I'm using 递归函数调用做得不好,所以我想将其重写为非递归函数。

    当前代码如下所示:

    void Parse(Foo foo)
    {
      A()
      for (;;)
      {
        B();
        if (C())
          return;
        if (D())
        {
          Run();
        }
        E();
      }
    }
    
    void Run()
    {
      X();
      if (Y())
      {
        Parse();
      }
      Z();
    }
    

    上面是伪代码。字母a、b、c、d、e、x、y和z是方法,parse()和run()也是方法。为了简单起见,我省略了各种参数和对象取消引用(例如,run是一个对象实例的方法,它需要一些参数)。

    不管怎样,我的问题是,如何将其转换为非递归代码?

    在我看来,等价的非递归代码是:

    void Parse(Foo foo)
    {
      //create a local stack variable to emulate recursion
      Stack<Foo> foos = new Stack<Foo>();
      foos.Add(foo());
    start_subroutine:
      A()
      for (;;)
      {
        B();
        if (C())
        {
          //instead of returning from a recursive call
          if (foos.Count > 1)
          {
            foo = foos.Pop();
            goto end_subroutine;
          }
          return;
        }
        if (D())
        {
          //instead of invoking Run as a subroutine, bring its functionality inline
          //Run();
          X();
          if (Y())
          {
            //instead of calling self recursively
            //Parse();
            //push onto a local stack variable and jump
            foos.Add(foo);
            goto start_subroutine;
          }
    end_subroutine:
          Z();
        }
        E();
      }
    }
    

    我同意这样做,但我不知道如何不使用goto;我也不记得有人写过这样的话,当goto是必要的时候。

    2 回复  |  直到 15 年前
        1
  •  2
  •   Mike    15 年前

    我觉得你走对了!在这种情况下,我看不出使用goto有什么真正的问题。代码中发生的事情非常清楚,人们试图避免直接跳转的唯一原因是,在读取别人的代码时,它会导致混乱。

    如果您保持它的结构整洁,并且在其他函数中包含大部分实现代码,那么这看起来完全合理。尤其是因为您只使用非递归代码进行分析:)

    祝你好运,不管你最后怎么做!

        2
  •  2
  •   Thorarin    15 年前

    我不能真的测试这个,但在我看来你可以替换 goto start_subroutine 具有

    A();
    continue;
    

    goto end_subroutine 具有

    Z();
    E();
    continue;
    

    不过,我不确定这是否真的更好。)