【问题标题】:Using recursive function instead of loops [closed]使用递归函数而不是循环[关闭]
【发布时间】:2018-05-08 01:03:17
【问题描述】:

我正在尝试使用递归构建评分矩阵,

    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)

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

【问题讨论】:

  • 不使用递归?
  • 递归并不是在所有情况下都可以真正加快代码速度,而只是一种解决无法通过迭代解决或适合递归的问题的方法
  • afaik 几乎所有的递归都可以用循环来完成......递归有时可以使它比循环更具可读性(或不)
  • @JoranBeasley:所有递归都可以通过循环和显式堆栈来完成。 一些递归可以只用一个循环来完成,就像这种情况。但你是对的,在某些情况下,递归情况更具可读性(即使不需要堆栈),在这些情况下,只要你的有界限制远低于堆栈深度,就值得这样做。

标签: python recursion


【解决方案1】:

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

不幸的是,递归函数受堆栈深度的限制。一些语言有尾调用消除,这意味着尾递归函数是没有界的。你的实现是尾递归的。但是 Python(故意)没有那个特性,所以没关系;您仍然只能处理长度不超过sys.getrecursionlimit()+1 的字符串。

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

还有一些技巧可以在 Python 中模拟尾调用消除,我将在下面讨论。但即使使用了最好的技巧,您的递归代码仍然比嵌套循环更长、不那么明显、不那么 Pythonic 并且更慢。

如果您这样做是为了完成家庭作业,那么您可能已经完成了。除非您可以选择编程语言,否则在这种情况下,您将需要选择一种消除尾调用的语言。如果您要为真实代码执行此操作,则应坚持使用原始嵌套循环 - 代码更简单,运行速度更快,并且没有堆栈限制,不需要任何 hacky 或复杂的东西。


在 CPython 中实现尾调用优化的最有效方法是修改编译函数的字节码,如 here。但这也是最骇人听闻的方式,而且它只在有限的情况下有效。

最简单的方法是修改你的函数以返回一个返回值而不是值的函数,然后使用蹦床将评估链接在一起(至少有两篇博客文章展示了这种技术,@987654324 @ 和 here)。但是,虽然这实现起来最简单,但它需要通过实际的递归函数进行更改,这使得它们更复杂且可读性更低。

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

【讨论】:

    猜你喜欢
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 2021-03-20
    • 1970-01-01
    • 2012-11-12
    • 2018-08-15
    相关资源
    最近更新 更多