【问题标题】:Converting Function with Two Successive "Tail" Recursive Calls to Iterative Function将具有两个连续“尾”递归调用的函数转换为迭代函数
【发布时间】:2018-10-24 19:20:37
【问题描述】:

我已经看到了很多关于如何将最后带有单个递归调用的函数转换为迭代版本的示例;但是,如果最后有两个递归调用呢?

这是我的意思的一个例子,在 Python 中:

def doit(x, y, L):
  if x < y:
    x += 1
  else:
    x -= 1
    y -= 1
  if y > 0:
    L.append(x)
    doit(x, y, L)
    doit(x - 1, y - 1, L)

#usage
L = []
doit(3, 5, L)
print(L)

请注意,两个递归调用都在最后。无论我在这两个递归调用之前在代码中做什么,是否有一种通用方法可以将这样的东西转换为迭代版本?请记住,我上面提供的只是一个示例。

【问题讨论】:

    标签: loops recursion stack iteration


    【解决方案1】:

    不,没有 generalsimple 方法可以解决尾递归情况。即使您最后有 1 个递归调用,但该函数不是尾递归(例如 return 5+foo(x)),也是如此。您必须显式维护一个堆栈,然后它甚至可以在最后有两个以上递归调用的情况下工作。

    要了解原因,请注意尾递归函数中的每个变量(即参数和局部变量)在任何给定时刻最多只能有一个可能的值。因此,您永远不需要在 RAM 中维护多个版本。因为在进行下一次递归调用的那一刻,一个好的编译器会销毁它们当前的版本并在它们当前所在的相同位置分配新版本。所以它基本上只是修改一个变量而不是分配新的变量。

    因此,对于没有“最大 1 版本”保证的普通递归函数,请在主循环之前声明一个堆栈。其中的每个元素都是所有参数的元组。在循环内部,获取堆栈的最后一个元素(并从堆栈中删除它)。然后只需在循环内复制/粘贴您的函数体。但是,除了进行下一次递归调用外,创建一个包含该调用的所有参数值的元素并将其压入堆栈。您的代码已修改:

    A = [] #your initial 'L'
    stack = [(2,4,A)] #push values of initial call
    while stack:
        x,y,L = stack.pop()
        print(x,y)
        if x < y:
            x += 1
        else:
            x -= 1
            y -= 1
        if y > 0:
            L.append(x)
            stack.append((x, y, L))
            stack.append((x - 1, y - 1, L))
    

    但是,只有当递归调用的顺序无关紧要时,他才会起作用,比如 dfs。否则,我对“内部堆栈”有一个想法,但这个答案已经太长了。

    【讨论】:

    • 您需要切换 stack.append() 语句的顺序。
    • 这仅适用于这个特定示例,这不是通用解决方案
    猜你喜欢
    • 1970-01-01
    • 2021-06-18
    • 2020-08-08
    • 2015-05-30
    相关资源
    最近更新 更多