【发布时间】:2010-10-06 14:38:35
【问题描述】:
据我所知,大多数递归函数都可以使用循环来重写。有些可能比其他的更难,但大多数都可以重写。
在什么情况下使用循环重写递归函数是不可能的(如果存在这种情况)?
【问题讨论】:
-
我怀疑你的意思是没有某种形式的堆栈就无法重写,是这样吗?
-
其实没有。我的意思是如果完全不可能使用循环重写它。我想以间接递归为例。
标签: recursion
据我所知,大多数递归函数都可以使用循环来重写。有些可能比其他的更难,但大多数都可以重写。
在什么情况下使用循环重写递归函数是不可能的(如果存在这种情况)?
【问题讨论】:
标签: recursion
我不知道递归函数不能转换为迭代版本的例子,但不切实际或效率极低的例子是:
树遍历
快速傅里叶
快速排序(以及其他一些 iirc)
基本上,任何你必须开始跟踪无限潜在状态的地方。
【讨论】:
在SICP 中,作者挑战读者想出一种纯粹的迭代方法来实现“计数变化”问题(here's an example 来自 Project Euler)。
但是已经给出了对您问题的严格答案 - 循环和堆栈可以实现任何递归。
【讨论】:
当您递归使用函数时,编译器会为您处理堆栈管理,这使递归成为可能。任何可以递归执行的操作,都可以通过自己管理堆栈来完成(对于间接递归,您只需确保不同的函数共享该堆栈)。
所以,不,没有什么可以用递归完成,也不能用循环和堆栈完成。
【讨论】:
每个递归函数都可以用一个循环来实现。
想想处理器做了什么,它在一个循环中执行指令。
【讨论】:
间接递归仍然可以转换为非递归循环;只需从其中一个函数开始,然后内联对其他函数的调用,直到你有一个直接递归函数,然后可以将其转换为使用堆栈结构的循环。
【讨论】:
一个极难从递归转换为迭代的例子是Ackermann function。
【讨论】:
任何递归函数都可以进行迭代(进入循环),但您需要自己使用堆栈来保持状态。
通常情况下,尾递归很容易转化为循环:
A(x) {
if x<0 return 0;
return something(x) + A(x-1)
}
可以翻译成:
A(x) {
temp = 0;
for i in 0..x {
temp = temp + something(i);
}
return temp;
}
其他可以翻译成尾递归的递归也很容易改变。另一个需要更多的工作。
以下内容:
treeSum(tree) {
if tree=nil then 0
else tree.value + treeSum(tree.left) + treeSum(tree.right);
}
翻译不是那么容易。您可以删除递归的一部分,但如果没有保持状态的结构,则另一部分是不可能的。
treeSum(tree) {
walk = tree;
temp = 0;
while walk != nil {
temp = temp + walk.value + treeSum(walk.right);
walk = walk.left;
}
}
【讨论】:
与其说它们不能使用循环来实现,不如说是递归算法的工作方式,它更清晰、更简洁(在许多情况下可以通过数学证明)一个函数是正确的.
很多递归函数可以写成尾循环递归,可以优化为循环,但这取决于算法和使用的语言。
【讨论】:
您始终可以使用循环,但您可能需要创建更多数据结构(例如模拟堆栈)。
【讨论】:
它们都可以写成一个迭代循环(但有些可能仍然需要一个堆栈来保持以前的状态以供以后的迭代使用)。
【讨论】: