使用递归函数而不是循环

时间:2013-11-18 19:25:58

标签: python recursion

我正在尝试使用递归

构建评分矩阵
    for i in range(1, len(str1))
        for j in range(1, len(str))
        #do something

我的代码:

def matrix_bulid(index_1, index_2):
    print(index_1, index_2)
    if index_1 == len(first_dna) and index_2 == len(second_dna):
        return
    elif index_2 == len(second_dna):
        return matrix_bulid(index_1 + 1, 1)
    else:
    #do something
            matrix_bulid(index_1, index_2 + 1)

但是在非常长的字符串中,我得到最大深度错误的东西。 有没有人知道怎么做?

1 个答案:

答案 0 :(得分:2)

如果你的目标是将嵌套的for循环变成一个简单的递归函数,那么你已经成功完成了。有一些错误(错误的缩进,在第二个递归情况下没有返回任何内容,...),但基本结构是健全的。

不幸的是,递归函数受到堆栈深度的限制。有些语言有尾调用消除,这意味着尾递归函数不受限制。而你的实现是尾递归的。但是Python(故意)没有这个功能,所以这并不重要;你仍然只能处理长达sys.getrecursionlimit()+1的字符串。

如果你的字符串是有界的,但是对于默认的递归限制(在CPython中为1000)有点太大,你可以使用sys.setrecursionlimit将其设置得更高。

在Python中也有模拟尾部调用消除的技巧,我将在下面讨论。但即使有最好的技巧,你的递归代码仍然比你的嵌套循环更长,更不明显,更少Pythonic,并且速度慢。

如果你正在为家庭作业做这件事,你可能已经完成了。除非您可以选择编程语言,否则您将需要选择具有尾调用消除功能的语言。如果您正在为真正的代码执行此操作,那么您应该坚持使用原始的嵌套循环 - 代码更简单,运行速度更快,并且没有堆栈限制,无需任何麻烦或复杂。


在CPython中实现尾调用优化的最有效方法是将编译函数的字节码修改为here。但这也是最黑客的方式,它只适用于有限的情况。

最简单的方法是修改函数以返回一个返回值而不是值的函数,然后使用trampoline将评估链接在一起(至少有两篇博客文章显示了这种技术,{{ 3}}和here)。但是,虽然这是最简单的实现,但它需要通过实际的递归函数进行更改,这会使它们更复杂,更不易读。

最好的权衡可能是使用在每个递归步骤中间插入蹦床的装饰器,因此您不需要显式延迟函数调用,如here所示。如果你有相互递归的函数,这可能会有点棘手,但很难弄清楚。而且实现很容易理解。它并不比字节码hackery慢得多。