Python 如何将此非尾部递归函数转换为循环或尾部递归版本?
我对这件事好奇了很久。对于人类来说,创建一个非尾部递归函数来获得一些复杂的东西是非常容易和优雅的,但是速度非常慢,很容易达到Python递归的极限:Python 如何将此非尾部递归函数转换为循环或尾部递归版本?,python,recursion,tail-recursion,Python,Recursion,Tail Recursion,我对这件事好奇了很久。对于人类来说,创建一个非尾部递归函数来获得一些复杂的东西是非常容易和优雅的,但是速度非常慢,很容易达到Python递归的极限: def moves_three(n, ini=0, med=1, des=2): '''give a int -> return a list ''' if n == 1: return ((ini,des),) return moves_three(n-1, ini=ini, med=des, des
def moves_three(n, ini=0, med=1, des=2):
'''give a int -> return a list '''
if n == 1:
return ((ini,des),)
return moves_three(n-1, ini=ini, med=des, des=med) + \
((ini, des),) + \
moves_three(n-1, ini=med, med=ini, des=des)
if __name__ == '__main__':
moves_three(100) # may be after several hours you can see the result.
len(moves_three(10000))
那么,如何将
移动\u three
更改为尾部递归1或循环(更好)?更重要的是,有没有关于这一点的文章?谢谢。即使使用迭代形式,也不会更快。问题不在于递归限制;你仍然比递归极限低一个数量级。问题是输出的大小是O(2^n)
。对于n=100
,您必须构建一个包含大约1000亿个元素的元组。不管你如何建造它;你永远不会完成
如果仍要将其转换为迭代,可以通过使用显式堆栈(而不是调用堆栈)来管理状态:
def moves_three(n, a=0, b=1, c=2):
first_entry = True
stack = [(first_entry, n, a, b, c)]
output = []
while stack:
first_entry, n1, a1, b1, c1 = stack.pop()
if n1 == 1:
output.append((a1, c1))
elif first_entry:
stack.append((False, n1, a1, b1, c1))
stack.append((True, n1-1, a1, c1, b1))
else:
output.append((a1, c1))
stack.append((True, n1-1, b1, a1, c1))
return tuple(output)
令人困惑,不是吗?堆栈上的元组
(True,n,A,b,c)
表示使用参数n,A,b,c
输入函数调用。元组(False,n,A,b,c)
表示在移动三个(n-1,A,c,b)
结束后返回(True,n,A,b,c)
调用。,所以不用麻烦制作尾部递归版本:)@theourtheye谢谢我知道这一点。Python有实现TCO的方法,我知道两种方法,所以两者都可以…@thefourtheye,但它们可以,解决递归问题。:)@学生们,使用装饰师没有多大意义。到循环的转换非常简单,将函数重构为循环不会花费太多时间,这也将避免装饰器和函数调用的所有开销。@Bakuriu是的,大多数尾部递归函数都可以转换为循环。。装饰师只是一个我觉得有趣的例子…非常感谢。我为你的答案制作了一个收益率版本,所以即使它非常巨大,它仍然可以输出。