当被要求使用非递归算法来解决问题时,人们经常使用堆栈,但实质上不是堆栈和递归相同吗?此外,当堆栈用于替换递归时,空间复杂度保持不变(渐近)。我没有遇到任何根本的区别 观察?
答案 0 :(得分:1)
您的应用程序堆栈大小比数据结构堆栈更受限制。只要您可以动态分配内存(实际上这次它依赖于应用程序 heap ),您就没有问题。
您提到的应用程序堆栈更加有限,并且它具有每个临时局部变量,函数参数,返回值,堆栈指针和ext的副本。这使它的尺寸比看起来更小。
答案 1 :(得分:0)
在某些情况下,Big-O复杂度可能相同,但使用显式堆栈的常数因素通常更好。此外,机器执行堆栈的大小通常相对较小,而显式(堆分配)堆栈可能会变得更大。
有时你会想要寻找一种完全不同的算法,这种算法恰好是非递归的,它会表现得更好。考虑一下天真的斐波纳契序列算法:
int f(int n)
{
if (n < 2)
{
return 1;
}
return f(n-2) + f(n-1);
}
此算法采用指数时间:(
非递归版本(在这种情况下实际上是一种“动态编程”)在n
中只是线性的,并且不使用堆栈:
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;
}
答案 2 :(得分:0)
是的,它完全是一样的。
使用堆栈而不是使用调用堆栈是一种解决方法(当一种语言的堆栈空间少于程序需要处理的最大值时),或者它是一种优化,可以节省一些空间,因为堆栈帧通常用一些没有TCO的语言来获取一些机器字,或者你不需要以相同的方式存储数据,因此即使每个项目的堆栈空间效率较低,它也会使总消耗量大大减少。 / p>
并非所有语言都需要它,在Racket语言中,它不能用于任何目的使用显式堆栈,因为堆栈没有限制,因为除了总计内存以外,即使非TCO也是如此调用(如树遍历)它仍然可以工作,直到所有内存都被消耗。
在Java中,启动程序时可以配置堆栈空间。它更喜欢读取递归代码,因此在恢复使用显式堆栈之前,请检查您的语言是否可以执行此操作。