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

Algorithm 将递归算法转换为带堆栈的迭代算法,algorithm,recursion,iteration,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

我的教授在课堂上给我们做了这个练习,要求我们用堆栈精确地模拟递归调用。这是递归算法:

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”)

该算法失败,因为在
stack\u.pop()
上,当堆栈为空时,我将弹出,因此出现运行时错误。我接近找到解决方案了吗


我非常感谢你的帮助

当您模拟递归调用时,您只会推动您知道应该返回的堆栈。但是,您并不是在推动上下文来知道将响应推送到哪个上下文

我建议你分多个步骤来解决这个问题

  • 将所有函数局部变量(
    T
    h
    ret
    s
    d
    )转换为递归函数外部的堆栈,使用显式的pop/push而不是声明它们,并期望它们在函数结束时消失。(提示:将
    ret
    保留在堆栈上,并在操作
    stack\u s
    stack\u d
    时将其弹出)这可能需要为第一次递归调用创建一个helper函数
  • 在函数中为您第一次调用它的位置以及您可以返回的每个位置添加标签
  • 转换为迭代,如下所示。为函数调用添加堆栈。它将包含函数中的位置标签。您不必进行递归调用,而是更改函数堆栈的顶部以说明在该调用中返回到何处,并推送一个新的堆栈以说明启动一个新函数,然后转到下一个循环迭代。(退出循环的条件是函数堆栈为空,您的答案将位于
    ret
    堆栈的顶部。)
  • 这是一个有点冗长但机械的过程。它应该会让你对电脑在正常情况下为你所做的一切表示感谢。:-)

    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