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)