在python中将递归转换为迭代

时间:2014-03-17 16:55:27

标签: python recursion python-3.3

我还是相对较新的Python,我刚刚写了一个执行Collatz Conjecture.的基本程序但是,我遇到了堆栈溢出,因为我已经递归地编写了程序,而不是迭代(根据本网站上的其他问题)。这个问题还有其他一些答案,但我不确定如何在我自己的程序中实现它们。简化版如下:(编辑:我刚刚翻译了一些代码以使其更简单,我实际上遇到了运行此问题的问题,但你知道发生了什么 - pastebin of actual code

def collatz(number):
    if number == 1:
        print('Finished!')

    if number % 2 == 0:
        number = number/2
        collatz(number)
    elif number % 2 != 0:
        number = (number*3) + 1
        collatz(number)

n = int(input('Pick a number'))
collatz(n)

这看起来相当简单,但我似乎无法理解这一点。我尝试了一个更简单的例子:

def fun(n):
    while n < 10:
        n += 1
        fun(n)

fun(1)

我试图通过迭代我在本网站上看到的例子来转换它

def fun(n):
    while n < 10:
        n += 1
        return n

fun(1)

但我不确定如何实现n的返回来迭代程序。

如果这是一个补救性问题,我道歉,但我似乎无法克服这个问题。

编辑:

solution

下面还有一些很好的通用解决方案。

5 个答案:

答案 0 :(得分:3)

一般来说,你的后两个例子是:

def recr_fun(n):
    if n >= 10:
        return n
    return recr_fun(n+1)

def iter_fun(n):
    while n < 10:
        n += 1
    return n # note identation

请注意,递归版本必须通过递归调用将结果传递回来,并且迭代版本在循环完成后返回

答案 1 :(得分:1)

你是对的,while循环在这里可以正常工作:

def collatz(number):
    number = int(number)
    while number != 1:
        if number % 2 == 0:
            number = number/2
        elif number % 2 != 0:  # could be just `else` -- either it's divisible by 2 or it isn't :)
            number = (number*3) + 1
    print("finished")

n = int(input('Pick a number'))
collatz(n)

在这种情况下,非递归形式主义实际上更清晰,因为你的函数实际上并没有返回任何东西。

答案 2 :(得分:1)

完成后你忘记了回来:

def collatz(number):
    if number == 1:
        print('Finished!')
        return # you are causing an infinite loop if you dont do this

    if number % 2 == 0:
        number = number/2
        collatz(number)
    elif number % 2 != 0:
        number = (number*3) + 1
        collatz(number)

您可以像下面那样清理代码:

def collatz(number):
    if number == 1:
        print('Finished!')
        return # you are causing an infinite loop if you dont do this

    if number % 2 == 0:  collatz(number/2)
    else:                collatz((number*3) + 1)

干杯!

答案 3 :(得分:0)

由于程序不正确,您会收到堆栈溢出:

def collatz(number):
    if number == 1:
        print('Finished!')
    elif number % 2 == 0:
        number = number/2
        collatz(number)
    elif number % 2 != 0:
        number = (number*3) + 1
        collatz(number)

这项工作很好没有堆栈溢出。但是,代码的迭代版本是

def iterCollatz(number):
    while number != 1:
        if number % 2 == 0:
            number = number / 2
        else:
            number = (number * 3) + 1
    print('Finished!')

答案 4 :(得分:0)

在大多数情况下,没有办法在算法上说'#34;如果我在这个递归函数上执行这些操作,它就会变为迭代。&#34;相反,你需要查看整个程序并查看它是如何工作的,然后了解如何使它在没有递归的情况下工作。例如,让我们编写一个递归解决方案来展平列表(包含列表和数字等)

def recurse_flatten(target):
    """recurse_flatten(list_of_lists) -> flat list"""
    accumulator = list()
    for element in target:
        if hasattr(element,"__iter__"):
            accumulator.extend(recurse_flatten(element))
        else:
            accumulator.append(element)
    return accumulator

如您所见,如果顶级元素具有属性"__iter__",则该函数会调用自身,这意味着它可以迭代。相反,我们可以这样做:

def iter_flatten(target):
    """iter_flatten(list_of_lists) -> flat list"""
    depth = 0
    targets = [iter(target)]
    accumulator = list()
    while True:
        try:
            element = next(targets[depth])
        except StopIteration:
            if depth == 0: return accumulator
            else:
                depth -= 1
                targets.pop()
        else:
            if hasattr(element,"__iter__"):
                targets.append(iter(element))
                depth += 1
            else: accumulator.append(element)

正如您所看到的,迭代版本更长,更冗长,但它永远不会嵌套。如果你有有限的堆栈空间,这可能是一件好事,但一般来说(至少如果你正在编写Python)代码越可读,就越好,让我现在告诉你,递归代码是更加可读。时间明智,你必须自己测试。在我的系统上:

# TEST DATA: [1, 2, [3, 4, 5, 6], 7, [8, [9, 10, 11]]]

# timeit.timeit(recurse_flatten)
10.985460426787078
# timeit.timeit(iter_flatten)
16.635406831330158