文章目录
- 遍历二叉树的方案
- 1. 使用递归实现二叉树的遍历
- 2. 使用栈实现二叉树的遍历
- 3. 知其二遍历结果,如何求第三种?
- 3.1 已知前序和中序,如何还原二叉树?(已知中序和后序求前序类似)
- 3.2 已知前序和中序,如何求解后序?
- 3.3 已知中序和后序,如何求前序?
- 3.4 已知前序和后序,如何求中序的结果?
遍历二叉树的方案
一颗非空二叉树由根节点和左右子树三个部分构成,(NLR进行排序总共有6种方式,由于对称性问题,主要讨论三种)。
- 先序遍历:
即先访问节点(Node)本身,然后访问左(left subtree)、右子树(right subtree) - 中序遍历:
即先访问左子树、然后再访问节点,最后访问节点。 - 后序遍历: 先访问左子树、在访问右子树,最后访问节点。 例图:
1. 使用递归实现二叉树的遍历
- 构建二叉树
class Node:
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left # 左子树
self.right = right # 右子树
- 递归实现二叉树的前序、中序和后序遍历:
# -*- coding: utf-8 -*-
class Node:
def __init__(self,value=None,left=None, right=None):
self.value = value
self.left = left
self.right = right
def preTraverse(root):
# 前序遍历
if root == None:
return
print(root.value, end=' ')
preTraverse(root.left)
preTraverse(root.right)
def midTraverse(root):
# 中序遍历
if root == None:
return
midTraverse(root.left)
print(root.value, end=' ')
midTraverse(root.right)
def afterTraverse(root):
# 后序遍历
if root == None:
return
afterTraverse(root.left)
afterTraverse(root.right)
print(root.value, end=' ')
# 测试:
if __name__ == '__main__':
root = Node()
root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
print('前序遍历:')
preTraverse(root)
print('\n中序遍历:')
midTraverse(root)
print('\n后序遍历:')
afterTraverse(root)
运行结果:
“D:\Program Files\Anaconda3\python.exe” C:/Users/lenovo/Desktop/二叉树/BinaryTree.py
前序遍历:
D B A C E G F
中序遍历:
A B C D E F G
后序遍历:
A C B F G E D
Process finished with exit code 0
2. 使用栈实现二叉树的遍历
# # -*- coding: utf-8 -*-
class Node:
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left
self.right = right
def preTraverse(self):
"""
使用栈结构实现先序遍历的思路:先将该二叉树整体推入到栈中,
根据栈后进先出的特性,先将栈取出:打印输出该二叉树的值,
因此需要先将二叉树的右节点推入栈结构中(如果存在的话)
然后再将二叉树的左节点推入栈中(如果存在的话)
下一次从栈中取的话就能达到先去左节点,后取右节点的效果。
"""
if self.value == None:
return
stack = [self]
while stack:
current = stack.pop()
print(current.value, end=' ')
if current.right:
stack.append(current.right)
if current.left:
stack.append(current.left)
def midTraverse(self):
"""
中序遍历需要执行打印顺序为:左子树、节点、右子树
需要先找到该二叉树的的最小左子树,然后从这颗左子树开始遍历节点和右子树
"""
if self.value == None:
return
stack = []
current = self
while len(stack) != 0 or current:
if current: # 不断递进,直到找到当前树的最小左子树
stack.append(current)
current = current.left
else: # 当前的栈中末尾的树已经是最小树时
temp = stack.pop()
print(temp.value, end=' ') # 打印出了当前树的节点后,开始对右子树动刀子
current = temp.right
def afterTraverse(self):
if self.value == None:
return
stack1 = [self]
stack2 = []
#
while stack1: # 使用了两个栈进行存储,因此从两个栈就构成了一个队列,先进先出
current = stack1.pop()
stack2.append(current)
if current.left:
stack1.append(current.left)
if current.right:
stack1.append(current.right)
# 直接遍历stack2输出即可:
while stack2:
print(stack2.pop().value, end=' ')
# 测试:
if __name__ == '__main__':
root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
print('前序遍历:')
root.preTraverse()
print('\n中序遍历:')
root.midTraverse()
print('\n后序遍历:')
root.afterTraverse()
输出结果与使用递归方式的结果相同。
3. 知其二遍历结果,如何求第三种?
3.1 已知前序和中序,如何还原二叉树?(已知中序和后序求前序类似)
- 由前序遍历的第一个可以确定根节点为D,通过对比中序遍历可以知道,左子树由ABC构成,右子树由EFG构成,但具体内容还得进一步分析;
- 同理左子树的前序遍历为BAC,中序遍历为ABC,可以确定该左子树的根节点为B,由中序遍历可知该节点的左子树为A,右子树为C。
- 同理对右子树的前序遍历为EGF,中序遍历为EFG,则可以确定右子树的根节点为E,右子树的左子树为空,右子树的右子树的根节点为G,其左子树为F。
则可以还原出原来的树的结构,最后可以推出树的结构。 - 由于篇幅限制,基于上述3个步骤的演示:在知道了前序和中序还原了二叉树。
3.2 已知前序和中序,如何求解后序?
例如:
已知前序遍历:D B A C E G F
中序遍历:A B C D E F G
求后序遍历:
A C B F G E D
使用python代码实现:(递归求解)
pre = ['D','B','A','C','E','G','F']
mid = ['A','B','C','D','E','F','G']
def find_after(pre, mid):
if not mid or not pre:
return None
troot = pre[0]
for ind, item in enumerate(mid):
if item == troot:
break
find_after(pre[1:ind+1], mid[:ind])
find_after(pre[ind+1:], mid[ind+1:])
print(troot, end=' ')
find_after(pre,mid)
注:该函数在求解长度为100000的二叉树数列(蓝桥杯算例):能够accept 91%的算例
3.3 已知中序和后序,如何求前序?
例如:
已知后序遍历:A C B F G E D
中序遍历:A B C D E F G
求前序遍历:
D B A C E G F
使用python代码实现:(递归求解)
mid = ['A','B','C','D','E','F','G']
after = ['A','C','B','F','G','E','D']
def find_pre(mid,after):
if not after or not mid:
return None
troot = after[-1]
for ind, item in enumerate(mid):
if item == troot:
break
print(troot,end=' ')
find_pre(mid[:ind],after[:ind])
find_pre(mid[ind+1:],after[ind:-1])
find_pre(mid,after)
3.4 已知前序和后序,如何求中序的结果?
由于知道前序和后序,不能得到唯一确定的二叉树,此处将不再讨论。