后序遍历的访问顺序为 左子树->右子树->根节点
递归的方式很简单,这里就不叙述了,考虑非递归方式
思路:
后序遍历跟前序和中序不同的地方在于,访问完左子树后,会回溯到父节点,此时不能访问父节点,访问完右子树后,回溯到父节点,此时才能访问父节点。所以回溯到父节点的时候,要判断上一次操作访问的是哪里,如果上一次操作访问的时左子树,那么不可访问当前节点,得先去访问当前节点的右子树,如果上一次操作访问的是右子树,那么可以访问当前节点。因此,要有一个指针来记录上一次操作访问的是哪个节点。这个指针加入的位置就是访问节点的位置。
核心代码
res = []
pNode = self.root
stack = []
preVisited =None
while(pNode != None or len(stack) != 0):
if (pNode != None):
stack.append(pNode)
pNode = pNode.left
else:
pNode = stack[-1]
if pNode.right == None or pNode.right == preVisited:
res.append(pNode.val)
stack.pop()
preVisited = pNode
pNode = None #防止被重复访问
else:
pNode = pNode.right
以节点4为例,因为节点4非空,压栈并访问其左子树,对于节点6,压栈,访问其左子树,以为左子树为None,看其父节点,因为父节点的右子树也为None,所以可以访问当前的父节点6(访问即出栈),并将节点6记为preVisited,并将pNode标记为None,这样可以避免下一次重复访问该节点。
进入下一轮循环后,因为pNode为None,要看此时栈顶的元素父节点4,并且其右子树不为空,且上次访问的节点不是节点7(上次访问的是6),此时进入右子树访问。访问完毕后preVisited更新为节点7,pNode为None。
进入下一轮循环,指针指向当前的父节点4,虽然其右子树不为空,但是其右孩子节点7是其上一次访问过的节点(pNode.right == preVisited),所以可以访问当前的父节点。
class Node:
def __init__(self,val):
self.val = val
self.left = None
self.right = None
class Traverse:
def __init__(self):
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node6 = Node(6)
node7 = Node(7)
node1.left = node2
node1.right = node3
node2.left = node4
node2.right = node5
node4.left = node6
node4.right = node7
self.root = node1
self.resRec =[]
def printResult(self):
print([6, 7, 4, 5, 2, 3, 1])
def postOrderTraverse(self):
res = []
pNode = self.root
stack = []
preVisited =None
while(pNode != None or len(stack) != 0):
if (pNode != None):
stack.append(pNode)
pNode = pNode.left
else:
pNode = stack[-1]
if pNode.right == None or pNode.right == preVisited:
res.append(pNode.val)
stack.pop()
preVisited = pNode
pNode = None #防止被重复访问
else:
pNode = pNode.right
print(res)
def postOrderRecursion(self):
self.helper(self.root)
print(self.resRec)
def helper(self,root):
if root != None:
self.helper(root.left)
self.helper(root.right)
self.resRec.append(root.val)