将递归算法转换为带有堆栈的迭代器

时间:2018-06-22 14:43:00

标签: algorithm recursion iteration

我的教授在课堂上给了我们这个练习,并要求准确地模仿带栈的递归调用。这是递归算法:

def algo(T, h):
    ret = -1
    s = 0
    d = 0

    if T != None:
        if T.left != None:
            s = algo(T.left, h + 1)
        if T.right != None:
            d = algo(T.right, h + 1)

        if s == 0 and d == 0:
            ret = h
        else:
            ret = s + d

    return ret

这是我尝试解决此问题的尝试(我使用了两个堆栈,一个用于保存T,另一个用于保存“ s”)

def algo_it(T, h):
    ret = -1
    s = 0
    d = 0

    curr = T
    next = None
    last = None

    stack_T = Stack()
    stack_S = Stack()

    while curr != None or not stack_T.empty():
        if curr != None:
            # First time entering the function
            ret = -1
            s = 0
            d = 0

            if curr.left != None:
                # Left recursive call
                h = h + 1
                next = curr.left

                # Save current T because it will be popped when going up
                # on recursion tree
                stack_T.push(curr)
            elif curr.right != None:
                # Right recursive call
                h = h + 1
                next = curr.right

                stack_T.push(curr)
            else:
                # Force going up on recursion tree
                next = None
        else:
            # Coming up from recursion tree
            curr = stack_T.top()

            if last != curr.right and curr.right != None:
                # We're here from the 1st recursive call (left)
                # We have to go in right recursive call now
                h = h + 1
                next = curr.right

                # We are returning from left, so ret = s = algo(T.left, h + 1)
                s = ret
                stack_S.push(s)

                ret = -1
                d = 0
            else:
                stack_T.pop()

                if curr.right != None:
                    s = stack_S.pop()
                    d = ret
                else:
                    s = ret
                    d = 0

                if s == 0 and d == 0:
                    ret = h
                else:
                    ret = s + d

        last = curr
        curr = next

    return ret

算法失败,因为在stack_S.pop()上,当堆栈为空时我弹出,因此出现运行时错误。我快要找到解决方案了吗?

非常感谢您的所有帮助!

1 个答案:

答案 0 :(得分:1)

当模仿递归调用时,您只压入了您知道应该返回的堆栈。但是,您并不是要让上下文知道将响应推送到哪个上下文。

我建议您分多个步骤来解决此问题。

  1. 使用递归函数将所有函数局部变量(Thretsd)转换为递归函数之外的堆栈显式弹出/推送,而不是声明它们,并期望它们在函数结束时消失。 (提示:将ret留在堆栈上,并在操作stack_sstack_d时将其弹出。)这可能需要为第一个递归调用创建一个辅助函数。
  2. 在函数中放置标签,以标识您首次调用它的位置以及可以返回的每个位置。
  3. 转换为迭代,如下所示。为函数调用添加堆栈。它将包含该功能所在位置的标签。无需进行递归调用,您可以更改函数堆栈的顶部以说出此调用中的返回位置,并推动一个新的调用以说出开始一个新函数,然后转到下一个循环迭代。 (退出循环的条件是函数堆栈为空,而您的答案将是ret堆栈的顶部。)

这是一个漫长但机械的过程。它应该使您对计算机通常为您完成的工作量有所赞赏。 :-)