先序遍历二叉树非递归
类似递归的思想,遇到一个节点先打印出来,然后依次访问左右节点。但是非递归借助栈来实现有所不同,应该先打印当前节点,然后依次入栈右节点和左节点,因为此时栈的插入顺序和弹出顺序相反。
节点的结构:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
先序遍历的Python代码:
def pre_order(head):
'''
二叉树先序遍历非递归实现
:param head: 头节点
:return: result列表类型
'''
if not head: # 空
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先输出
result.append(node.val)
# 栈的弹出顺序与入栈顺序相反 因此先入右再入左
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
中序遍历二叉树非递归
中序遍历就不能马上打印当前节点了,得先打印左孩子的节点,所以得先把有左孩子的节点压栈。从头结点开始,不断把有左孩子的节点压栈,直到左孩子为空,这样能保证先打印出左下角的节点。如果当前节点没有左孩子了,就出栈打印一个出来。如果这个节点有右节点,就继续上一步骤,对有左子树的疯狂压栈。
复杂点来说,就是把有左节点的疯狂压栈,没了就弹一个出来打印,再看看有没有右节点,有就转到右节点,然后再重复左节点的疯狂压栈~~~
def mid_order(head):
'''
二叉树中序遍历非递归实现
1.当前节点如有左节点就不断压栈 无左节点就可以出栈打印
2.打印出栈的节点若有右子树则将右节点执行1的步骤
:param head: 头结点
:return: result列表类型
'''
if not head: #空
return []
stack, result = [], []
node = head
# 循环条件:1.栈非空则还可以输出 2.栈空但是节点非空说明还有节点可以压栈
while node or len(stack) != 0:
if not node: # 如果节点为空 证明没有左子树 弹出一个
node = stack.pop()
result.append(node.val)
node = node.right #尝试是否有右节点
else: # 节点非空 压栈 尝试是否有左子树
stack.append(node)
node = node.left
return result
后序遍历二叉树非递归
后序遍历是 左-右-中 的顺序,反过来就是 中-右-左,这就是二叉树镜像(左右节点互换)的先序遍历顺序。也就是说,镜像二叉树的先序遍历逆序后就是二叉树后序遍历的顺序。所以在刚才先序遍历的代码基础上,改一下左右节点入栈顺序,再在最后逆序一下就可以了。
def post_order(head):
'''
后序遍历二叉树非递归 后序遍历是 左-右-中
反过来就是 中-右-左 其实就是先序遍历镜像二叉树(即左右互换)
:param head: 头节点
:return: result[::-1] 逆序
'''
if not head:
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先输出
result.append(node.val)
# 先压栈左节点再压右节点 所以输出就是先右后左
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return result[::-1] # 将 中-右-左 逆序变为 左-右-中
最后附上全部代码,含测试案例
# -*- coding:utf-8 -*-
'''
author: James_J
time: 2020/02/21
'''
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def pre_order(head):
'''
二叉树先序遍历非递归实现
:param head: 头节点
:return: result列表类型
'''
if not head: # 空
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先输出
result.append(node.val)
# 栈的弹出顺序与入栈顺序相反 因此先入右再入左
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
def mid_order(head):
'''
二叉树中序遍历非递归实现
1.当前节点如有左节点就不断压栈 无左节点就可以出栈打印
2.打印出栈的节点若有右子树则将右节点执行1的步骤
:param head: 头结点
:return: result列表类型
'''
if not head: #空
return []
stack, result = [], []
node = head
# 循环条件:1.栈非空则还可以输出 2.栈空但是节点非空说明还有节点可以压栈
while node or len(stack) != 0:
if not node: # 如果节点为空 证明没有左子树 弹出一个
node = stack.pop()
result.append(node.val)
node = node.right
else: # 节点非空 压栈 尝试是否有左子树
stack.append(node)
node = node.left
return result
def post_order(head):
'''
后序遍历二叉树非递归 后序遍历是 左-右-中
反过来就是 中-右-左 其实就是先序遍历镜像二叉树(即左右互换)
:param head: 头节点
:return: result[::-1] 逆序
'''
if not head:
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先输出
result.append(node.val)
# 先压栈左节点再压右节点 所以输出就是先右后左
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return result[::-1] # 将 中-右-左 逆序变为 左-右-中
if __name__ == '__main__':
l1 = TreeNode(1)
l2 = TreeNode(2)
l3 = TreeNode(3)
l4 = TreeNode(4)
l5 = TreeNode(5)
l6 = TreeNode(6)
l1.left = l2
l1.right = l3
l2.left = l4
l2.right = l5
l3.left = l6
print('pre_order', pre_order(l1))
print('mid_order', mid_order(l1))
print('post_order', post_order(l1))