【问题标题】:How to generally translate a recursive program into an iterative one?通常如何将递归程序转换为迭代程序?
【发布时间】:2020-04-26 13:17:25
【问题描述】:

例如,将 BST 的前序遍历和有序遍历从递归转换为迭代相对简单。但是后订购更难。

这是原来的递归BST遍历函数:

Python 3

def traverse_rec(node):  # traversal of sub-tree at node.
    # pre-order work here:
    # print(node.val, end=' ')
    if node.lft:
        traverse_rec(node.lft)

    # in-order work here:
    print(node.val, end=' ')

    # post-order work here:
    # print(node.val, end=' ')
    if node.rt:
        traverse(node.rt),

我发现了一些递归函数的迭代版本(前序、序中、后序 BST 遍历),例如 here,但我正在寻找遵循 what the computer does with it's call stack 的迭代实现,以便我可以同样轻松转换后序 BST 遍历,更一般地,将递归代码转换为迭代。因此,每次调用函数时都应将“帧”推入帧堆栈,该函数记录在函数返回时继续执行的位置,以及调用函数所需的任何变量,这些变量可能会被被调用函数更改。帧在函数返回时从帧堆栈中弹出。

【问题讨论】:

    标签: python recursion iteration


    【解决方案1】:

    这是我使用 frame_stack 对迭代翻译的递归:

    def traverse_iter(node):
        # Iterative bst traversal. A (node, state) tuple is pushed onto frame_stack where a recursive call would occur.
        # state defines where to pick up the processing on return (on pop).
        # state: 0: Did not just return into this frame.
        #        1: Just returned from left child.
        #        2: Just returned from right child.
        # Only states 1 and 2 get pushed onto the frame_stack.
        # Generally, state would include any variables that are needed on return that get changed on the frame change
        # in addition to the program counter (pc).
        # Here, each node has all the data (val) needed, and state 1 or 2 acts as a pc to determine where to pick up
        # on return.
        frame_stack = []
        state = 0  # Didn't just return from a child(function call).
        while True:
            if node is None:    
                if frame_stack:  # Returning up recursion tree:
                    node, state = frame_stack.pop()
                else:            # or completed traversal.
                    break
    
            if state == 0:
                # Execute pre-order work here.
                #print(node.val, end=' ')
                if node.lft:  # Emmulate recursive call into left child.
                    frame_stack.append((node, 1))
                    node = node.lft
                    continue
    
            if state == 0 or state == 1:
                # Execute in-order work here
                print(node.val, end=' ')
    
                if node.rt:
                    frame_stack.append((node, 2))
                    node = node.rt
                    state = 0       # State to descend into child.
                    continue
    
            # Returning from a right child or there was none:
            # Execute post-order work here.
            # print(node.val, end=' ')
            node = None     # finished with this node (and all below it).
    

    一旦我“明白”了,我发现开发和理解上述内容相当简单,而且似乎我使用的模式通常可以扩展到任何递归到迭代翻译,因为它基于计算机的功能。我基本上将递归函数调用转换为变量的更新,这些变量被更改为新函数(此处为节点到子节点),并将它们的原始值与 pc 一起推送到帧堆栈(此处为节点)(此处为状态);根据需要添加了最小的支持逻辑。

    我想知道是否有人可以提供一个示例,其中帧有效负载需要超过 (node, state) 才能从我们离开的函数返回中拾取,或者简化我的 BST 遍历(同时保持它 pre-, in-,和后订购一般)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-26
      • 2017-03-05
      • 2017-03-08
      相关资源
      最近更新 更多