尽管dancancode的答案讨论的是诸如原始递归问题,递归问题和递归可枚举问题之类的各种问题,但是恕我直言,这个问题更多地是关于简单的递归或迭代。
我想知道递归是否是一个问题的唯一解决方案,那么堆栈迭代是否是唯一的其他解决方案?
不,有很多不同的计算模型。但是,lambda演算(递归的基础)和图灵机(迭代的基础)是最受欢迎的计算模型。另一个流行的计算模型是μ递归。
什么是计算模型?
很长一段时间以来,数学家都想研究计算的本质。他们想知道可以计算哪些问题(即哪些问题有解决方案)以及哪些问题无法计算(即哪些问题无解决方案)。他们还想知道计算的性质(例如,相对于其输入大小,计算解决方案需要花费多少时间等)。
但是,只有一个问题:“计算”是一个非常抽象的术语。您如何处理一些不具体的事情?这就是数学家需要他们可以推理的计算模型的原因。计算模型体现了“计算的本质”。这意味着,如果存在可以解决的问题,那么在每种计算模型中都必须有一种算法来解决该问题。
我认为它们是等效的:如果递归有效,那么迭代肯定会起作用,反之亦然。
对,那是正确的。该教会图灵论题本质规定,计算每一个模型是电力等同。因此,您可以使用递归(即lambda演算)执行的所有操作也可以使用迭代(即图灵机)进行。
实际上,世界上大多数计算机都基于图灵机。因此,每台计算机仅使用迭代。但是,您的计算机仍可以执行递归程序。这是因为编译器将递归程序转换为迭代机器代码。
另外,我不确定为什么递归被认为效率低下,并且经常导致堆栈溢出,而使用堆栈的迭代却没有。递归仅以用户不可见的自动方式使用堆栈。
这是因为操作系统处理进程的方式。大多数操作系统对堆栈大小施加最大限制。在我的Linux操作系统上,最大堆栈大小为8192 KB,这不是很多。用于ulimit -s在符合POSIX的操作系统上查找默认堆栈大小。这就是为什么使用太多递归会导致堆栈溢出的原因。
另一方面,可以在进程执行过程中动态增加堆的大小(只要可用空间可用)。因此,在使用迭代时(甚至在使用显式堆栈时),您不必担心内存不足。
此外,递归通常比迭代慢,因为调用函数需要上下文切换,而在迭代中您只需要修改指令指针(即跳转,可能是有条件的)。
但是,这并不意味着迭代总是比递归更好。递归程序通常比迭代程序更小,更易于理解。另外,在某些情况下,编译器可以通过尾部调用优化(TCO)完全消除上下文切换。这不仅使递归与迭代一样快,而且确保堆栈大小不会增加。
有趣的是,可以通过将所有递归程序转换为连续传递样式(CPS)来使其成为尾递归。因此,CPS和TCO可以完全消除隐式调用堆栈的需求。一些用于函数式编程语言的编译器和解释器以新颖的方式使用此功能。