总是可以将递归转换为尾部递归吗?在
我很难将下面的Python函数转换为尾部递归函数。在
def BreakWords(glob):
"""Break a string of characters, glob, into a list of words.
Args:
glob: A string of characters to be broken into words if possible.
Returns:
List of words if glob can be broken down. List can be empty if glob is ''.
None if no such break is possible.
"""
# Base case.
if len(glob) == 0:
return []
# Find a partition.
for i in xrange(1, len(glob) + 1):
left = glob[:i]
if IsWord(left):
right = glob[i:]
remaining_words = BreakWords(right)
if remaining_words is not None:
return [left] + remaining_words
return None
我不确定是否总是这样,但大多数递归函数都可以作为尾部递归来实现。除了尾递归优化不同于尾递归优化。在
尾递归与正则递归的区别
递归函数中必须存在两个元素:
“正则”递归函数将(2)保存在堆栈帧中。
正则递归函数的返回值由两种类型的值组成:
我们来看一个例子:
例如,帧f(5)“存储”它自己计算的结果(5)和f(4)的值。如果我调用factorial(5),就在堆栈调用开始崩溃之前,我有:
^{pr2}$请注意,除了我提到的值之外,每个堆栈还存储函数的整个范围。所以,递归函数f的内存使用量是O(x),其中x是我必须进行的递归调用的数量。所以,如果我需要1kb的RAM来计算阶乘(1)或阶乘(2),我需要~100k来计算阶乘(100),依此类推。在
一个尾部递归函数,将(2)放入它的参数中。
在尾部递归中,我使用参数将每个递归帧中部分计算的结果传递给下一个。让我们看看阶乘示例,Tail Recursive:
让我们看看它的阶乘(4)中的帧:
看到区别了吗?在“regular”递归调用中,返回函数递归地组成最终值。在尾部递归中,它们只引用基本情况(最后一个被评估的)。我们称累加器跟踪旧值的参数。在
递归模板
正则递归函数如下所示:
要在尾部递归中转换它,我们:
看:
你的例子:
我做了这样的事:
为了消除您所做的for语句,我使用2个累加器执行递归助手函数。一个存储结果,一个存储我当前尝试的位置。在
尾部优化
由于尾部调用堆栈的非边界情况中没有存储状态,所以它们并不那么重要。一些语言/解释器然后用新堆栈替换旧堆栈。因此,在没有堆栈帧约束调用数量的情况下,尾部调用的行为就像for循环。在
但不幸的是,Python并不是其中之一。当堆栈大于1000时,将出现运行时错误。Mr. Guido 认为由于尾部调用优化(由错误抛出的帧引起)导致的对调试目的的清晰性比特性更重要。真可惜。Python有很多很酷的函数,而尾部递归在它之上会很棒:/
相关问题 更多 >
编程相关推荐