Python并不支持尾递归优化,我们只是使用其语法来描述这个概念。
尾递归就是操作的最后一步是调用自身的递归。它和一般的递归不同在对内存的占用,普通递归创建stack累积而后计算收缩,尾递归只会占用恒量的内存(和迭代一样)。
我们看一个对比:
普通递归
def recsum(x):
if x == 1:
return x
else:
return x + recsum(x - 1)
调用recsum(5)
,Python调试器中发生如下状况:
recsum(5)
5 + recsum(4)
5 + (4 + recsum(3))
5 + (4 + (3 + recsum(2)))
5 + (4 + (3 + (2 + recsum(1))))
5 + (4 + (3 + (2 + 1)))
5 + (4 + (3 + 3))
5 + (4 + 6)
5 + 10
15
这个曲线就代表内存占用大小的峰值,从左到右,达到顶峰,再从右到左收缩。而我们通常不希望这样的事情发生,所以使用迭代,只占据常量stack space(更新这个栈!而非扩展它)。
尾递归
def tailrecsum(x, running_total=0):
if x == 0:
return running_total
else:
return tailrecsum(x - 1, running_total + x)
调用tailrecsum(5)
,Python调试器中发生如下状况:
tailrecsum(5, 0)
tailrecsum(4, 5)
tailrecsum(3, 9)
tailrecsum(2, 12)
tailrecsum(1, 14)
tailrecsum(0, 15)
15
观察到,tailrecsum(x, y)
中形式变量y
的实际变量值是不断更新的,对比普通递归就很清楚,后者每个recsum()
调用中y
值不变,仅在层级上加深。所以,尾递归是把变化的参数传递给递归函数的变量了。
有些编译器会把尾递归优化成循环,上面的例子用循环表述:
for i in range(6):
sum += i
Ref
https://www.zhihu.com/question/20761771/answer/19996299
https://zh.wikipedia.org/wiki/%E5%B0%BE%E8%B0%83%E7%94%A8