递归转非递归 栈模拟 Recursive to Non-recursive stack simulated 总结

120 篇文章 1 订阅

As is well known, recursive codes could be transformed into non-recursive codes leveraging stack. However, simulating the recursive procedure should take care of what should be done before and after each function call. The recursive codes generally could be classified into 3 categories: preorder, inorder and postorder. For the preorder, the tag to distinguish the left node or right node is not necessary. But for the inorder and postorder, a tag is significant. The following is the basic flow for recursive the non-recursive.

def NonRecursive(self, root):
    stack = []
    while ((Go to the Most Left Leaf) or (Stack is Not Empty)):
        while (Go to the Most Left Leaf):
            stack.append(Left Leaf Function Call)
            #Go to deeper left node
        if (Stack is Not Empty):
            cur = stack.pop()
            if (cur["tag"] == 'l'):
                # Do the right thing
            elif (cur["tag"] == 'r'):
                root = cur["node"]
                # Do the right thing

再快速总结一下非递归遍历的两种套路:

冲到左下角看根法:
1. 先序和另外两种的区别:先序边冲边访问,另外两种弹栈后才访问
2. 中序和后序的区别:中序弹栈top后,根指向top右节点,两种情况都work;后序还得多个标记

栈顶元素按序数儿子法:
1.先序逆着儿子大小数,后序顺着数
2.后序要额外空间

Here're examples for tree traversal: 

from itertools import permutations


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def p1(self, root):
        if (root == None):
            return
        print(root.val)
        self.p1(root.left)
        self.p1(root.right)

    def p2(self, root):
        stack = []
        while (root != None or stack):
            while (root != None):
                print(root.val)
                stack.append(root)
                root = root.left
            if (stack):
                root = stack.pop()
                root = None if root == None else root.right

    def i1(self, root):
        if (root == None):
            return
        self.i1(root.left)
        print(root.val)
        self.i1(root.right)

    def i2(self, root):
        stack = []
        while (root != None or stack):
            while (root != None):
                stack.append({'node': root, 'tag': 'l'})
                root = root.left
            if (stack):
                cur = stack.pop()
                if (cur["tag"] == 'l'):
                    print(cur["node"].val)
                    if (cur["node"].right != None):
                        stack.append({'node': cur["node"].right, 'tag': 'r'})
                    root = None
                elif (cur["tag"] == 'r'):
                    root = cur["node"]

    # i3 is better, inorder doesn't need extra flg in fact
    def i3(self, root):
        stack = []
        while (root != None or stack):
            while (root != None):
                stack.append(root)
                root = root.left
            if (stack):
                root = stack.pop()
                print(root.val)
                root = root.right if (root.right != None) else None

    def post1(self, root):
        if (root == None):
            return
        self.post1(root.left)
        self.post1(root.right)
        print(root.val)

    def post2(self, root):
        stack = []
        while (root != None or stack):
            while (root != None):
                stack.append({'node': root, 'tag': 'l'})
                root = root.left
            if (stack):
                cur = stack.pop()
                if (cur["tag"] == 'l'):
                    stack.append({'node': cur["node"], 'tag': 'r'})
                    root = None if cur["node"].right == None else cur["node"].right
                elif (cur["tag"] == 'r'):
                    print(cur["node"].val)
                    root = None

    def get_not_visited_child(self, parent, visited):
        if (parent.left and parent.left not in visited):
            return parent.left
        if (parent.right and parent.right not in visited):
            return parent.right
        return None

    # 新玩法,先序后序都可以这么玩
    def post3(self, root):
        sta = [root]
        visited = {root}
        revert = []
        while (sta):
            next = self.get_not_visited_child(sta[-1], visited)
            while (next):
                sta.append(next)
                visited.add(next)
                next = self.get_not_visited_child(sta[-1], visited)
            if (sta):
                revert.append(sta.pop().val)
        return revert


    # 新玩法,先序后序都可以这么玩
    def p3(self, root):
        res = []
        sta = [root]
        while (sta):
            top = sta.pop()
            res.append(top.val)
            if (top.right):
                sta.append(top.right)
            if (top.left):
                sta.append(top.left)
        return res


n1 = TreeNode(1)
n2 = TreeNode(2)
n3 = TreeNode(3)
n4 = TreeNode(4)
n5 = TreeNode(5)
n6 = TreeNode(6)
n7 = TreeNode(7)
n1.left = n2
n1.right = n3
n2.left = n4
n2.right = n5
n3.left = n6
n3.right = n7
s = Solution()
s.p1(n1)
print(s.p3(n1))

Another two examples, Hanoi is inorder:

from itertools import permutations


def h1(src, des, via, n):
    if (n == 0):
        return
    # Before recursive call of left child, des and via swap for left child going deeper
    h1(src, via, des, n - 1)
    # After recursive call, print will be done for left child
    print("{0}:{1}-->{2}".format(n, src, des))
    # Before recursive call of right child, via and src swap for right child going deeper
    h1(via, des, src, n - 1)
    # After recursive call of right child, nothing will be done again


def h2(src, des, via, n):
    stack = []
    while (stack or n > 0):
        # Deeper for left child
        while (n > 0):
            stack.append({'src': src, 'des': via, 'via': des, 'n': n - 1, 'child': 'left'})
            des, via = via, des
            n = n - 1
        if (stack):
            top = stack.pop()
            if (top['child'] == 'left'):
                src, des, via, n, child = top['src'], top['via'], top['des'], (top['n'] + 1), top['child']
                print("{0}:{1}-->{2}".format(n, src, des))
                stack.append({'src': via, 'des': des, 'via': src, 'n': n - 1, 'child': 'right'})
                n = 0
            elif (top['child'] == 'right'):
                src, des, via, n, child = top['src'], top['des'], top['via'], (top['n'] + 1), top['child']
                n = n - 1
#h3 is better, inorder doesn't need extra flg in fact
def h3(src, des, via, n):
    stack = []
    while (stack or n > 0):
        # Deeper for left child
        while (n > 0):
            stack.append({'src': src, 'des': des, 'via': via, 'n': n})
            des, via = via, des
            n = n - 1
        if (stack):
            top = stack.pop()
            src, des, via, n = top['src'], top['des'], top['via'], top['n']
            print("{0}:{1}-->{2}".format(n, src, des))
            n -= 1
            src, via = via, src

h1('A', 'C', 'B', 3)
print('------------------')
h2('A', 'C', 'B', 3)
print('------------------')
h3('A', 'C', 'B', 3)

Quicksort is preorder:

from itertools import permutations


def partition(a, l, r):
    i, j = l, r
    pivot = a[(i + j) // 2]
    while (i <= j):  # Ensure i, j are not at the same position after partition, so i <=j instead of i <j
        while (a[i] < pivot):
            i = i + 1
        while (a[j] > pivot):
            j = j - 1
        if (i <= j):
            a[i], a[j] = a[j], a[i]
            i, j = (i + 1), (j - 1)
    return i, j


def q1(a, l, r):
    i, j = partition(a, l, r)
    if (i < r):
        q1(a, i, r)
    if (j > l):
        q1(a, l, j)
    return a

#preorder doesn't need tag
def q2(a, l, r):
    stack = []
    while (stack or l < r):
        while (l < r):
            i, j = partition(a, l, r)
            if (j > l):
                stack.append({'left': l, 'right': j})
            l, r = i, r

        if (stack):
            top = stack.pop()
            l, r = top['left'], top['right']
    return a

#preorder doesn't need tag
def q3(a, l, r):
    stack = []
    while (stack or l <= r):
        while (l <= r):
            i, j = partition(a, l, r)
            stack.append({'l':l, 'r':r, 'i':i, 'j':j})
            l, r = i, r
        if (stack):
            cur = stack.pop()
            l, r = cur['l'], cur['j']
    return a


for perm in permutations([1, 2, 3, 3, 4, 5, 6], 7):
    y = q3(list(perm), 0, 6)
    print(y)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值