简体   繁体   English

如何将这个非尾递归函数转换为循环或尾递归版本?

[英]How to convert this non-tail-recursion function to a loop or a tail-recursion version?

I've been curious for this for long. 我一直很好奇这个。 It is really very easy and elegant for human to create a non-tail-recursive function to get something complicated, but the speed is very slow and easily hit the limit of Python 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=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)) 

So, how to change moves_three to a tail recursion one or a loop (better)? 那么,如何将moves_three改为尾递归一个或一个循环(更好)? More important, are there any essays to talk about this? 更重要的是,有没有论文可以谈论这个? Thanks. 谢谢。

Even with an iterative form, this isn't going to get any faster. 即使使用迭代形式,这也不会更快。 The problem isn't the recursion limit; 问题不在于递归限制; you're still an order of magnitude below the recursion limit. 你仍然比递归限制低一个数量级。 The problem is that the size of your output is O(2^n) . 问题是输出的大小是O(2^n) For n=100 , you have to build a tuple of about a thousand billion billion billion elements. 对于n=100 ,您必须构建一个大约1000亿亿元素的元组。 It doesn't matter how you build it; 你如何建造它并不重要; you'll never finish. 你永远不会完成。

If you want to convert this to iteration anyway, that can be done by managing state with an explicit stack instead of the call stack: 如果你想将它转换为迭代,那么可以通过使用显式堆栈而不是调用堆栈来管理状态来完成:

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)

Confusing, isn't it? 令人困惑,不是吗? A tuple (True, n, a, b, c) on the stack represents entering a function call with arguments n, a, b, c . 堆栈上的元组(True, n, a, b, c)表示使用参数n, a, b, c进入函数调用。 A tuple (False, n, a, b, c) represents returning to the (True, n, a, b, c) call after moves_three(n-1, a, c, b) ends. 元组(False, n, a, b, c)表示在moves_three(n-1, a, c, b)结束后返回(True, n, a, b, c)调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM