前言:相信很多同学都被二叉树非递归dfs的前中后序遍历方法弄的头疼。网上的答案,什么前中后序遍历各有一套写法,还有什么一个栈的写法,两个栈的写法。看起来能理解,一闭眼自己写都记不住。今天介绍一种用一种简单方法解决前中后序遍历的方法。
重点:二叉树非递归算法就是对递归算法的模拟。对于二叉树的深度优先搜索,其实前中后序遍历,它的搜索路径是一样的,区别就是在于节点的打印时机
比如如上图示,该二叉树遍历顺序是,1 2 4 2 5 7 5 2 1 ......
对于一个有左右叶子结点的节点2,它被路线中出现过3次,第一次从1节点到2节点,第二次从4节点到2节点,第三次从5节点到2节点。
对于一个缺失左右叶子节点的节点,如5,7,可以添加叶子结点None,此时该节点在路线上的也是被经过3次,如下图节点5
所有第一次进入该节点(从父节点进入)就被打印的,叫先序遍历,第二次进入该节点(从左子叶进入)被打印的叫中序遍历,第三次进入该节点(从右子叶进入)被打印的叫后序遍历
于是,我们可以把整个遍历过程记录下来,如下:
(1, 'first'), (2, 'first'), (4, 'first'), (4, 'middle'), (4, 'last'), (2, 'middle'), (5, 'first'), (7, 'first'), (7, 'middle'), (7, 'last'), (5, 'middle'), (5, 'last'), (2, 'last'), (1, 'middle').....
其中,first,middle,last是对这个节点第几次进入的一个标识flag,first代表第一次进入该节点,middle代表第二次进入该节点,last代表第三次进入该节点。这个遍历过程,其实已经完全表达了二叉树图形与遍历顺序,同时,first,middle,last又可以表示先序、中序、后序遍历的顺序
如果我们有了这个遍历顺序的list,然后按照first这个flag去过滤这个list,就能得到先序遍历的顺序。同理,按middle,last这个flag过滤,就能得到中序、后序遍历的顺序
遍历过程的获得:
1、初始化:建立一个临时temps= [],最终遍历顺序outputs = [],当前节点cur = None, 起始temps压入1节点和它的标识(1节点, 'first')
当前节点cur = None
最终outputs = []
临时temps= [(1节点, 'first')]
2、temps头部pop出 (1节点, 'first'), 将此节点压入outputs ,当前节点cur=(1节点, 'first'), 判断flag=‘first’,代表第一次访问,将[(2节点, 'first'), (1节点, 'middle'), (3节点, 'first'),(1节点, 'last')]压入temps的头部
cur = (1节点, 'first')
outputs = [(1节点, 'first')]
temps= [(2节点, 'first'),(1节点, 'middle'), (3节点, 'first'), (1节点, 'last')]
3、第二次,循环重复2步骤,temps头部pop出 (2节点, 'first'), 将此节点压入outputs.....,temps压入[(4节点, 'first'), (2节点, 'middle'), (5节点, 'first'),(2节点, 'last')]
cur = (2节点, 'first')
outputs = [(1节点, 'first'), (2节点, 'first')]
temps= [(4节点, 'first'), (2节点, 'middle'), (5节点, 'first'),(2节点, 'last'),(1节点, 'middle'), (3节点, 'first'), (1节点, 'last')]
4、第三次,循环重复,但由于节点4下没有子节点,只要压入[(4节点, 'middle'),(4节点, 'last')]
cur = (4节点, 'first')
outputs = [(1节点, 'first'), (2节点, 'first'), (4节点, 'first'),]
temps= [(4节点, 'middle'),(4节点, 'last'),(2节点, 'middle'), (5节点, 'first'),(2节点, 'last'),(1节点, 'middle'), (3节点, 'first'), (1节点, 'last')]
5、第四次,当前节点cur的flag是middle或者是last时,直接将cur压入outputs即可
cur = (4节点, 'middle')
outputs = [(1节点, 'first'), (2节点, 'first'), (4节点, 'first'),(4节点, 'middle')]
temps= [(4节点, 'last'),(2节点, 'middle'), (5节点, 'first'),(2节点, 'last'),(1节点, 'middle'), (3节点, 'first'), (1节点, 'last')]
第五次:
cur = (4节点, 'last')
outputs = [(1节点, 'first'), (2节点, 'first'), (4节点, 'first'),(4节点, 'middle'),(4节点, 'last')]
temps= [(2节点, 'middle'), (5节点, 'first'),(2节点, 'last'),(1节点, 'middle'), (3节点, 'first'), (1节点, 'last')]
6、重复如上步骤,直到temps为空
树的定义:
class Node:
def __init__(self,value=None,left=None,right=None):
self.value=value
self.left=left #左子树
self.right=right #右子树
tree = Node(1, Node(2, Node(4, ), Node(5, Node(7, ), None)), Node(3, None, Node(6, None, Node(8, Node(9, ), Node(10, )))))
核心代码:
def dfs(root):
temps = [(root, 'first')]
outputs = []
while temps:
cur_q = temps.pop()
cur_node = cur_q[0]
flag = cur_q[1]
outputs.append(cur_q)
if flag == 'first':
temps.append((cur_node, 'last'))
if cur_node.right != None:
temps.append((cur_node.right, 'first'))
temps.append((cur_node, 'middle'))
if cur_node.left != None:
temps.append((cur_node.left, 'first'))
return outputs
outputs = dfs(tree)
#深度优先的遍历过程
all_values = [(i[0].value, i[1]) for i in outputs]
#先序遍历
pre_order = [i[0] for i in all_values if i[1] == 'first']
#中序遍历
middle_order = [i[0] for i in all_values if i[1] == 'middle']
#后序遍历
last_order = [i[0] for i in all_values if i[1] == 'last']
print(all_values)
print(pre_order)
print(middle_order)
print(last_order)
结果:
all_values:
[(1, 'first'), (2, 'first'), (4, 'first'), (4, 'middle'), (4, 'last'), (2, 'middle'), (5, 'first'), (7, 'first'), (7, 'middle'), (7, 'last'), (5, 'middle'), (5, 'last'), (2, 'last'), (1, 'middle'), (3, 'first'), (3, 'middle'), (6, 'first'), (6, 'middle'), (8, 'first'), (9, 'first'), (9, 'middle'), (9, 'last'), (8, 'middle'), (10, 'first'), (10, 'middle'), (10, 'last'), (8, 'last'), (6, 'last'), (3, 'last'), (1, 'last')]
#先序遍历
[1, 2, 4, 5, 7, 3, 6, 8, 9, 10]
#中序遍历
[4, 2, 7, 5, 1, 3, 6, 9, 8, 10]
#后序遍历
[4, 7, 5, 2, 9, 10, 8, 6, 3, 1]
核心代码也就十几行,关键是模拟遍历的顺序,再从中提取先中后序遍历顺序。
本文地址:https://blog.csdn.net/doufuxixi/article/details/109629820
希望与广大网友互动??
点此进行留言吧!