Algorithm 递归与堆栈

Algorithm 递归与堆栈,algorithm,recursion,Algorithm,Recursion,我想知道递归是否是问题的唯一解决方案,那么堆栈迭代是否是唯一的其他解决方案?我认为它们是等价的:如果递归有效,那么迭代肯定会有效,反之亦然 另外,我不知道为什么递归被认为是低效的,并且经常导致堆栈溢出,而使用堆栈的迭代则不会。递归只是以用户看不见的自动方式使用堆栈。有所谓的原始递归函数,可以用循环重写。然后是一类称为递归的函数,必须递归定义。最后一个类是递归可枚举函数 著名的Ackermann函数是递归函数,但不是原始递归函数 在Computerphile youtube频道上有一段关于这个主题

我想知道递归是否是问题的唯一解决方案,那么堆栈迭代是否是唯一的其他解决方案?我认为它们是等价的:如果递归有效,那么迭代肯定会有效,反之亦然


另外,我不知道为什么递归被认为是低效的,并且经常导致堆栈溢出,而使用堆栈的迭代则不会。递归只是以用户看不见的自动方式使用堆栈。

有所谓的原始递归函数,可以用循环重写。然后是一类称为递归的函数,必须递归定义。最后一个类是递归可枚举函数

著名的Ackermann函数是递归函数,但不是原始递归函数

在Computerphile youtube频道上有一段关于这个主题的精彩视频:

递归肯定是有效的。考虑合并排序()的GLIMC实现是递归的。< /P> 请注意,尾部递归有一个常见的编译器优化,它将递归函数编译成一个循环。

虽然我们讨论了不同类型的问题,如问题、问题和问题,但是这个问题更直接或更简单

我想知道递归是否是问题的唯一解决方案,那么堆栈迭代是否是唯一的其他解决方案

不,有很多不同的计算模型。然而,(递归的基础)和(迭代的基础)是最流行的计算模型。另一种流行的计算模型是

什么是计算模型?

长期以来,数学家们都想研究计算的本质。他们想知道哪些问题可以计算(即哪些问题有解)哪些问题不能计算(即哪些问题没有解)。他们还想知道计算的性质(例如,相对于输入大小计算解决方案需要多少时间,等等)

然而,只有一个问题:“计算”是一个非常抽象的术语。你如何解释一些不具体的东西?这就是数学家需要一个计算模型的原因,他们可以对此进行推理。计算模型抓住了“计算的本质”。这意味着,如果有一个可以计算的问题,那么在每个计算模型中都必须有一个算法来计算它

我认为它们是等价的:如果递归有效,那么迭代肯定会有效,反之亦然

是的,没错。本质上说,每种计算模型的功率都是相等的。因此,您可以使用递归(即lambda演算)进行的所有操作也可以使用迭代(即图灵机)进行

事实上,世界上大多数计算机都是基于图灵机的。因此,每台计算机只使用迭代。尽管如此,您的计算机仍然可以执行递归程序。这是因为编译器将递归程序转换为迭代机器代码

另外,我不知道为什么递归被认为是低效的,并且经常导致堆栈溢出,而使用堆栈的迭代则不会。递归只是以用户看不见的自动方式使用堆栈

这是因为操作系统处理进程的方式。大多数操作系统对堆栈的大小施加最大限制。在我的Linux操作系统上,最大堆栈大小是8192KB,这不是很多。使用
ulimit-s
查找与POSIX兼容的操作系统上的默认堆栈大小。这就是使用过多递归导致堆栈溢出的原因

另一方面,可以在进程执行时动态增加堆的大小(只要可用空间可用)。因此,在使用迭代时,您不必担心内存不足(即使在使用显式堆栈时)

此外,递归通常比迭代慢,因为调用函数需要一段时间,在迭代过程中,您只需要修改指令指针(即跳转,可能是有条件的)

然而,这并不意味着迭代总是比递归好。递归程序通常比迭代程序更小,更容易理解。此外,在某些情况下,编译器可以通过(TCO)完全消除上下文切换。这不仅使递归和迭代一样快,而且确保堆栈大小不会增加


有趣的是,所有递归程序都可以通过将程序转换为(CPS)来实现尾部递归。因此,CPS和TCO可以一起使用。函数式编程语言的一些编译器和解释器在中使用此功能。

递归效率低下,不是因为隐式堆栈,而是因为开销。它会导致堆栈溢出,因为分配给每个进程的堆栈空间量是有限的,并且远远小于分配给它的堆空间量。进程通常需要比堆栈空间多得多的堆空间。因此,最好尽量避免使用堆栈。如果编译器执行,递归可以和迭代一样快。当分配给进程的堆栈内存量(在进程创建时)耗尽时,会发生堆栈溢出。每次扩展调用堆栈时(通常是通过方法调用或在特殊情况下是递归调用),都会消耗调用堆栈。这并不一定是低效的,这取决于您使用的语言。请看这个问题@AaditMShah尽管递归中没有上下文切换(除非这是您所说的寄存器保存/恢复、堆栈帧设置和IP跳转,但是您的术语不寻常,并且与您发布的链接不一致)。在这两种情况下,这都不是白天和晚上的区别。我测试了缓存二叉树中7个节点的预序遍历:递归每个节点3.6ns,显式堆栈每个节点2.3ns