显式堆栈比递归更好



我们可以使用堆栈和递归以相反的顺序打印链表。我的老师说,使用显式堆栈更好,因为递归也使用堆栈,但必须维护许多其他参数。即使我们从stack使用std::stack,引用外部库不是也会占用时间吗?与使用递归解决方案相比,使用显式堆栈如何节省时间/空间?

递归涉及到隐式堆栈的使用。这是由用于编译代码的编译器在后台实现的。编译器创建的这个后台堆栈称为"调用堆栈"。调用堆栈可以使用堆栈数据结构来实现,该堆栈数据结构存储关于计算机程序的活动子程序的信息。

每个子例程调用都使用调用堆栈中的一个称为堆栈帧的帧。当函数返回一个值时,它的堆栈帧会从调用堆栈中弹出。

递归调用堆栈与显式调用堆栈

堆栈溢出

这两个堆栈之间的根本区别在于编译器为程序的调用堆栈分配的空间是固定的。这意味着,如果你不确定预期的递归函数调用的最大数量,并且调用的数量远远超过了在给定时间点分配给堆栈的空间所能处理的数量,那么就会出现堆栈溢出。另一方面,如果定义了一个显式堆栈,那么它是在编译器运行时分配给程序的堆空间上实现的。你猜怎么着,堆大小不是固定的,可以在运行时根据需要动态增加。您真的不必担心显式堆栈溢出。

空间与时间

在特定情况下,哪一个速度更快?在不支持递归相关优化(如尾部递归的尾部调用优化(的语言中,显式堆栈上的迭代可能比递归更快。

什么是Tail递归

尾递归是递归的一种特殊情况,其中递归函数在递归函数调用后不再进行任何计算,即函数的最后一步是对递归函数的调用。

什么是尾调用优化(TCO(

尾部调用优化可以避免为函数分配新的堆栈帧,因为调用函数只会返回从被调用函数获得的值。

因此,支持尾部调用优化的编译器/语言在调用堆栈中只使用一个堆栈帧来实现对递归函数的调用。如果您的编译器/语言不支持此功能,那么使用显式堆栈将节省大量空间和时间。

Python不支持尾调用优化。这样做的主要原因是要有一个完整而清晰的堆栈跟踪,从而实现高效的调试。几乎所有的C/C++编译器都支持尾调用优化。

当使用多个参数时,有时显式控制堆栈有助于简化事情。然而,递归解决方案使源代码的大小更小,更易于维护。

结论

最后,没有固定的答案。对于特定的场景,需要考虑许多因素,如可伸缩性、代码可维护性、所使用的语言/编译器等。最好的方法是同时使用这两种方法来实现解决方案,在将2个解决方案部署到生产设置之前,在输入集上计时并分析峰值空间利用率。

参见维基百科-递归与迭代

最新更新