非递归方式遍历二叉树
二叉树的遍历按照访问根节点与子节点的顺序分为先序(根,左,右)、中序(左、根、右)、后序(左、右、根)三种。通常会使用递归的方式进行遍历,实现起来非常简单。
假设结点的定义如下:
class Node:
value = None
left = None
right = None
先序遍历的一般实现如下:
def preorder_traverse(node):
if node is None:
return
do_something(node)
preorder_traverse(node.left)
preorder_traverse(node.right)
中序遍历的一般实现如下:
def inorder_traverse(node):
if node is None:
return
inorder_traverse(node.left)
do_something(node)
inorder_tranverse(node.right)
后序遍历的一般实现如下:
def postorder_traverse(node):
if node is None:
return
postorder_traverse(node.left)
postorder_traverse(node.right)
do_something(node)
递归方式直观易懂容易实现。在限定不使用递归的方式,通过一个辅助的栈,也能实现以上 3 种遍历。在处理时需要注意,栈是固定的后进先出的数据结构,要注意数据顺序。原来都是先访问左结点后右结点,那么在压栈时就要先右结点后左结点。
先序遍历的非递归实现如下:
def preorder_traverse(node):
stack = Stack()
if node:
stack.push(node)
while stack.length() > 0:
cur = stack.pop()
do_something(cur)
if cur.right:
stack.push(cur.right)
if cur.left:
stack.push(cur.left)
中序和后序遍历,需要辅助的数据来确定结点是否已经访问过(通过调整树结构也可以达到相同目的,但不太优雅),节点定义调整为:
class Node:
value = None
left = None
right = None
visited = False
那么中序遍历为:
def inorder_traverse(node):
stack = Stack()
if node:
stack.push(node)
while stack.length() > 0:
cur = stack.pop()
if cur.visited:
do_something(cur)
else:
if cur.right:
stack.push(cur.right)
stack.push(cur)
if cur.left:
stack.append(cur.left)
cur.visited = True
后序遍历为:
def postorder_traverse(node):
stack = Stack()
if node:
stack.push(node)
while stack.length() > 0:
cur = stack.pop()
if cur.visited:
do_something(cur)
else:
stack.push(cur)
if cur.right:
stack.push(cur.right)
if cur.left:
stack.push(cur.left)
cur.visited = True
中序和后序遍历中,把同一个父结点做了两次压栈操作,这里还有优化的空间,通过判断减少压栈操作。先序遍历也可写成与中序和后序相同结构的方式,使用 visited 变量记录结点是否已访问,然后用相同的压栈方式处理。