构建二叉树
已知前序遍历与中序遍历或已知后序遍历和中序遍历可以构建唯一的二叉树
根据前序遍历与中序遍历建树
class Tree_Node():def __init__(self,val):self.val = valself.left = Noneself.right = None
# 构建二叉树
# 根据前序遍历与中序遍历构建二叉树
# 前序遍历[3,9,2,1,7]
# 中序遍历[9,3,1,2,7]
# 后序遍历[9,1,7,2,3]
# 根据前序遍历,确定树的构建顺序
# 根据中序遍历,确定子节点的数量关系
# 前序遍历中,第一层树节点为{根:3},{左子树:9},{右子树:2,1,7}
# 第二层节点为:{叶节点:2},{左:1},{右:7}
# 利用中序遍历来表示:前序遍历中单签节点及叶子结点的索引范围
# 前序遍历中:根节点:i=0,在中序遍历中索引范围为{l:0,r:len(nums)}
# 前序遍历中:左子树:i+1,在中序遍历中的索引范围为:{l,m-1:中序遍历中根节点左侧数值}
# 前序遍历中:右子树:i+1+(m-l:剩余左子树的数量),在中序遍历中的索引范围为:{m+1中序遍历中根节点右侧数值,r}
# 利用递归,逐步更新左右子树的索引范围,即可实现利用前序便利与中序遍历数组构建唯一二叉树def dfs1(preorder,inorder,i,l,r):# print("当前高度的根节点所在右子树中的索引{}".format(i))# print("当前左右边界l:{} and r:{}".format(l,r))if r-l < 0 or i >r:return None# 初始化根节点root = Tree_Node(preorder[i])#中序遍历中根节点的索引m = inorder[preorder[i]]#左子树root.left = dfs1(preorder,inorder,i+1,l,m-1)# 右子树root.right = dfs1(preorder,inorder,i+1+(m-l),m+1,r)return root
def build_tree_basepre(preorder,inorder):inorder = {value:key for key,value in enumerate(inorder)}l = 0r = len(preorder)-1i = 0root = dfs1(preorder,inorder,i,l,r)return rootpreorder = [3,9,2,1,7]
inorder = [9,3,1,2,7]
pre_tree = build_tree_basepre(preorder,inorder)
print(pre_tree.right.right.val)
根据后序遍历与中序遍历建树
# 中序遍历[9,3,1,2,7]
# 后序遍历[9,1,7,2,3]
# 根据前序遍历,确定树的构建顺序
# 根据中序遍历,确定子节点的数量关系
# 前序遍历中,第一层树节点为{根:3},{左子树:9},{右子树:1,7,2}
# 第二层节点为:{叶节点:2},{左:1},{右:7}
# 利用中序遍历来表示:前序遍历中单签节点及叶子结点的索引范围
# 后序遍历中:根节点:i=r,在中序遍历中索引范围为{l:0,r:len(nums)}
# 后遍历中:右子树:i=i-1,在中序遍历中的索引范围为:{l,m-1:中序遍历中根节点左侧数值}
# 后遍历中:左子树:i = i-1-(m-1-l):剩余左子树的数量),在中序遍历中的索引范围为:{m+1中序遍历中根节点右子树,r}
# 利用递归,逐步更新左右子树的索引范围,即可实现利用前序便利与中序遍历数组构建唯一二叉树
def dfs2(postorder,inorder,i,l,r):# 初始化根节点if r-l <0 or i < 0 :return Noneprint("当前高度的根节点所在右子树中的索引{}".format(i))print("当前左右边界l:{} and r:{}".format(l,r))root = Tree_Node(postorder[i])#中序遍历中根节点的索引m = inorder[postorder[i]]#左子树# print("创建左子树")root.left = dfs2(postorder,inorder,i-1-(m-l-1),l = l,r = m-1)# 右子树,i为初始化右子的根节点# print("创建右子树")root.right = dfs2(postorder,inorder,i-1,m+1,r)return root
def build_tree_baseafter(afterorder,inorder):inorder = {value:key for key,value in enumerate(inorder)}l = 0r = len(afterorder)-1i = rroot = dfs2(afterorder,inorder,i,l,r)return root
postorder = [9,1,7,2,3]
inorder = [9,3,1,2,7]post_tree = build_tree_baseafter(postorder,inorder)
print(post_tree.right.right.val)
总结
- 前序遍历中节点之间的关系为根节点->左子树->右子树,根据这个顺序将根节点为i,左子树为:i+1,右子树为i+1+(左子树的数量);根据中序遍历,确定i的取值范围(中序遍历的特点是左子树->根节点->右子树,可以区分左子树与右子树存包含的子节点数量关系),首先确定中序遍历中的根节点所在索引m进而可以划分左子树与右子树之间的索引区间左子树:[l:m-1];右子树:[m+1,r];利用递归实现二叉树的构建。
值得注意的一点是,二叉树构建子树的递归条件(边界条件为,r-l>0,即数组区间不能小于0,其中当i>r) - 利用后序遍历与中序遍历构建二叉树则是利用后序遍历数组:左子树->右子树->根节点;则利用根节点为i=r,右子树i = i-1,左子树:i-1-(剩余左子树节点个数:m-1-l)