与使用堆栈相比,递归通常被认为是一种过时的遍历方法吗?

时间:2009-04-28 01:31:44

标签: recursion stack

我一直在阅读几个人们选择使用Stack而不是递归的地方。这是因为递归被认为是完成工作的过时方法,或者这两种方法在不同的环境中是否同样适用?

5 个答案:

答案 0 :(得分:15)

没有。恰好相反。递归是表达一类问题的自然方式。如果你没有递归,堆栈是一种模拟它的方法。

例如,请参阅此question。或者考虑一下标准的递归函数:计算 n -th Fibonacci数。

您会记得Fibonacci numbers是系列

0,1,1,2,3,5,8,13, ...

定义为F n = F n-1 + F n-2

这可以写为递归定义

基本情况:
F(0)= 0
F(1)= 1
递归步骤:
F(n)= F(n-1)+ F(n-2)

所以,你有F(0)= 0,F(1)= 1,F(2)= F(0)+ F(1)= 1,等等。

计算这个的简单程序(在C中只是为了咧嘴)是:

int fib(int n) {
    /* we'll ignore possible negative arguments, see Wikipedia */
    switch(n) {
       case 0: return 0; break;
       case 1: return 1; break;
       default: return fib(n-1)+fib(n-2); break;
    }
}

请注意该程序与原始定义的对应程度如何?

问题是,C管理调用堆栈中的所有中间结果。有些语言没有被定义为这样做(我唯一可以想到的是旧的FORTRAN,但我确信还有其他语言)。如果您使用汇编程序或旧FORTRAN编写,则必须管理自己的堆栈以跟踪这些中间结果。

答案 1 :(得分:10)

迭代通常比递归更快/更少开销。使用递归,我们隐式使用机器的堆栈作为我们的堆栈 - 我们“免费”获得 - 但我们支付昂贵的函数调用(以及随之而来的机器堆栈管理)的成本。

但递归函数通常更易于编写和阅读。

通常,可以使用递归编写函数,将其保留为瓶颈,然后将其替换为使用显式堆栈的迭代函数。

答案 2 :(得分:6)

更新了以包含鱼鳞修正。

使用堆栈是消除recursion

的标准技术

另请参阅:What is tail-recursion?

Tail-Recursion的示例(可以使用迭代删除):

public class TailTest
{   
    public static void Main()
    {       
        TailTest f = new TailTest();
        f.DoTail(0);
    }

    public void DoTail(int n)
    {       
        int v = n + 1;      
        System.Console.WriteLine(v);    

        DoTail(v);   // Tail-Recursive call
    }
}

答案 3 :(得分:4)

如果您处于编译语言/环境中,尾调用会增加堆栈(不应用尾调用优化(TCO)),那么最好避免深度递归,并且可能使用堆栈数据结构的迭代解决方案是首选

另一方面,如果您所在的语言/环境支持使用尾调用进行迭代,或者递归深度总是很小,那么递归通常是一个很好/优雅的解决方案。

(这有点过于宽泛,但总的来说,我绝不会将递归称为“过时”。)

答案 4 :(得分:3)

不,不,我认为现代开发人员应该在几毫秒内强调可读性和易维护性。

如果问题是递归的,我完全建议你的解决方案是递归的。

此外,您最终可能会引入一些不受欢迎的错误,以强制执行迭代/堆叠解决方案。