Recursion Isn';t使用与递归相同的堆栈?

Recursion Isn';t使用与递归相同的堆栈?,recursion,stack,Recursion,Stack,当要求使用非递归算法来解决问题时,人们通常使用堆栈,但本质上堆栈和递归不一样吗?。此外,当使用堆栈替换递归时,空间复杂度保持不变(渐近)。有什么根本性的区别是我没有做到的吗 注意?您的应用程序堆栈大小比数据结构堆栈更有限。只要您能够动态分配内存(实际上这次它取决于应用程序堆),您就不会有问题 您的应用程序堆栈(如前所述)更为有限,而且它具有每个临时局部变量、函数参数、返回值、堆栈指针和ext的副本。这使得它的大小比看起来更小。在某些情况下,Big-O复杂性可能相同,但使用显式堆栈的常量因子通常更

当要求使用非递归算法来解决问题时,人们通常使用堆栈,但本质上堆栈和递归不一样吗?。此外,当使用堆栈替换递归时,空间复杂度保持不变(渐近)。有什么根本性的区别是我没有做到的吗 注意?

您的应用程序堆栈大小比数据结构堆栈更有限。只要您能够动态分配内存(实际上这次它取决于应用程序堆),您就不会有问题


您的应用程序堆栈(如前所述)更为有限,而且它具有每个临时局部变量、函数参数、返回值、堆栈指针和ext的副本。这使得它的大小比看起来更小。

在某些情况下,Big-O复杂性可能相同,但使用显式堆栈的常量因子通常更好。此外,机器执行堆栈的大小通常相对较小,而显式(堆分配)堆栈可能会变得更大

有时,您会想寻找一种完全不同的算法,这种算法恰好是非递归的,性能会好得多。考虑天真的斐波那契数列算法:

int f(int n)
{
    if (n < 2)
    {
         return 1;
    }

    return f(n-2) + f(n-1);
}

是的,完全一样

使用堆栈而不是调用堆栈是一种变通方法(当一种语言的堆栈空间小于程序需要处理的最大值时)或者,这是一种可能会节省一些空间的优化,因为堆栈框架通常使用不具备TCO的语言中的一些机器字,或者您不需要以相同的方式存储数据,因此即使堆栈的每项空间效率较低,也会使总消耗量大大减少

虽然并非所有语言都需要它,但在语言机架中,使用显式堆栈并没有任何用途,因为堆栈上没有限制,因为除了程序拥有的总内存之外,即使使用非TCO调用(如树遍历),它仍然可以工作,直到所有内存被消耗为止


在Java中,启动程序时可以配置堆栈空间。它更喜欢读取递归代码,所以在恢复使用显式堆栈之前,请检查您的语言是否可以这样做。

这取决于您的语言。检查应用程序堆栈通常比检查堆分配的堆栈更容易。当转储跟踪时,几乎在每个调试器中都可以看到机器堆栈;指向堆分配堆栈的指针可能已损坏。实际上,您是对的。使用现代编辑器和调试器,您的情况更为突出。但由于位置的原因,应用程序堆栈将允许更快的访问。@RAY66如果堆栈数据结构基于动态内存分配和指针重定向(这是大多数情况下的情况),则这是正确的。您仍然可以通过预先分配所需的对象空间来提高性能,该空间的数量可以预见,这将增加堆栈中引用的局部性。@RAY:由于必须维护机器堆栈,这里的局部性应该会变得微不足道。(优化器在理解循环方面比理解递归要好得多)但对于所有性能问题,只有使用探查器进行测量才能真正了解。我明白你的意思,但我的问题是从概念的角度来看,它们不是一个吗?@RAY:这取决于算法。如果使用显式堆栈模拟递归,请确定。您正在模拟递归,所以希望您的模拟操作类似。但是大多数时候,当有人要求一个“非递归解决方案”时,他们想要一个完全不同的算法。让我重新表述一下这个问题:“堆栈和递归不一样吗?”@RAY:我想我已经回答了你的问题。有没有办法在不隐式或显式使用堆栈ADT的情况下模拟递归?谢谢!我只想知道这些。
int f(int n)
{
    int fMinusOne = 1;
    int fMinusTwo = 1;
    for (int idx = 1; idx < n; ++idx)
    {
        int next = fMinusOne + fMinusTwo;
        fMinusTwo = fMinusOne;
        fMinusOne = next;
    }

    return fMinusOne;
}