在不使用递归的情况下重写递归函数

时间:2010-12-12 14:10:10

标签: algorithm recursion rewrite non-recursive

我正在重写一些现有代码,其中递归调用不容易实现也不需要。 (在Fortran 77中,如果你必须知道的话。)我已经考虑过从头开始编写一个堆栈以跟踪所需的调用,但这看起来很糟糕,而且我宁愿不在数组中分配内存。递归并不深。 (我不相信Fortran 77也支持动态数组大小。)

关于如何采用明显的递归函数并以非递归方式重写它而不浪费堆栈空间的一般解决方案的任何其他建议?

非常感谢, 老麦克斯特

3 个答案:

答案 0 :(得分:15)

如果你的代码使用尾递归(也就是说,函数直接返回每个递归调用的结果而没有任何其他处理)那么就可以在没有堆栈的情况下强制重写函数:

function dosomething(a,b,c,d) 
{
  // manipulate a,b,c,d
  if (condition) 
    return dosomething(a,b,c,d) 
  else
    return something;
}

分为:

function dosomething(a,b,c,d) 
{
  while (true) 
  {
    // manipulate a,b,c,d
    if (condition) continue;
    else return something;
  }
}

没有尾递归,使用堆栈(或类似的中间存储)是唯一的解决方案。

答案 1 :(得分:3)

可以写成循环的经典递归函数是Fibonacci函数:

 function fib(n)
 {
     // valid for n >= 0
     if (n < 2)
         return n;
     else
         return fib(n-1) + fib(n-2);
 }

但是如果没有memoization,则需要使用O(N)堆栈空间进行O(exp ^ N)操作。

可以改写:

 function fib(n)
 {
     if (n < 2)
        return n;
     var a = 0, b = 1;
     while (n > 1)
     {
         var tmp = a;
         a = b;
         b = b + tmp;
         n = n - 1;
     }   
     return b;
 }

但这涉及到函数如何工作的知识,不确定它是否可以推广到自动过程。

答案 2 :(得分:2)

大多数递归函数可以很容易地重写为循环,浪费空间 - 这取决于函数,因为许多(但不是全部)递归算法实际上依赖于那种存储(尽管循环版本通常更有效在这些情况下也是如此。