遞迴轉非遞迴 棧模擬 Recursive to Non-recursive stack simulated 總結

taoqick發表於2018-09-07

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

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"]

    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

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.post1(n1)
print('------------------')
s.post2(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
 
h1('A', 'C', 'B', 3)
print('------------------')
h2('A', 'C', 'B', 3)

A better hanoi version:

#A better python version
#call: push to stack
#enter calling: pop from stack
def h2(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, 'child': 'left'})
            des, via = via, des
            n = n - 1
        if (stack):
            top = stack.pop()
            if (top['child'] == 'left'):
                print("{0}:{1}-->{2}".format(top['n'], top['src'], top['des']))
                if (top['n'] > 1):
                    stack.append({'src': top['via'], 'des': top['des'], 'via': top['src'], 'n': top['n']-1, 'child': 'right'})
            elif (top['child'] == 'right'):
                src, des, via, n, child = top['src'], top['des'], top['via'], top['n'], top['child']

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)

 

相關文章