Python实现二叉树重建
通常树有如下几种遍历方式:
- 前序遍历:先访问根结点,再访问左子结点,最后访问右子结点。
- 中序遍历:先访问左子结点,再访问根结点,最后访问右子结点。
- 后序遍历:先访问左子结点,再访问右子结点,最后访问根结点。
- 层序遍历:即广度优先遍历,先访问一级节点,后是二级节点…
最少需要两种遍历方式,才能重建二叉树。但前序和后序构建的二叉树不唯一,因为前序和后序在本质上都是将父节点与子结点进行分离,但并没有指明
左子树和右子树的能力,因此得到这两个序列只能明确父子关系,而不能确定一个二叉树。总之,必须要有中序才能构建,因为没有中序,就没办法确定
树的形状。
根据前序和中序遍历重建二叉树
思路:
前序遍历序列中,第一个数字总是树的根结点的值。在中序遍历序列中,根结点的值在序列的中间,
左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。剩下的我们可以递归来实现,具体如图:
前序遍历顺序:root — preorder of left branch — preorder of right branch
中序遍历顺序:inorder of left branch — root — inorder of right branch
1 | class TreeNode: |
根据中序遍历和后序遍历重建二叉树
思路:
在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。而在后序遍历序列中,根节点位于序列的最后。剩下的我们可以递归来实现。
中序遍历顺序:inorder of left branch — root — inorder of right branch
后序遍历顺序:postorder of left branch — postorder of right branch — root
1 | class TreeNode: |
根据前序遍历和后序遍历重建二叉树
因为前序和后序在本质上都是将父节点与子结点进行分离,但并没有指明左子树和右子树的能力,因此得到这两个序列只能明确父子关系,而不能确定一个二叉树, 如:

总之,必须要有中序才能构建,因为没有中序,你没办法确定树的形状。
思路:
前序遍历顺序:root — preorder of left branch — preorder of right branch
后序遍历顺序:postorder of left branch — postorder of right branch — root
假如说最终的二叉树可以被序列化的表述为 [1, 2, 3, 4, 5, 6, 7],那么其前序遍历为 [1] + [2, 4, 5] + [3, 6, 7],而后序遍历为 [4, 5, 2] + [6, 7, 3] + [1]。如果我们知道左分支有多少个结点,我们就可以对这些数组进行分组,并用递归生成树的每个分支。
算法:
我们令左分支有 L 个节点。我们知道 左分支的头节点 为 pre[1],但它也出现在 左分支的后序表示的最后。所以 pre[1] = post[L-1](因为结点的值具有唯一性),因此 L = post.indexOf(pre[1]) + 1。
现在在我们的递归步骤中,左分支由 pre[1 : L+1] 和 post[0 : L] 重新分支,而右分支将由 pre[L+1 : N] 和 post[L : N-1] 重新分支。
1 | class TreeNode: |
二叉树重建总结
一、根据前序、中序遍历重建二叉树
- 根据前序序列的第一个元素建立根结点
- 在中序序列中找到根结点位置,确定左右子树
- 递归由左子树的前序序列和中序序列建立左子树
- 递归由右子树的前序序列和中序序列建立右子树
二、根据中序、后序遍历重建二叉树
- 根据后序序列的最后一个元素建立根结点
- 在中序序列中找到根结点位置,确定左右子树
- 递归由左子树的后序序列和中序序列建立左子树
- 递归由右子树的后序序列和中序序列建立右子树
三、前序、后序遍历重建二叉树(不唯一)
- 根据前序序列的第一个元素建立根结点
- 令左分支有 L 个节点。根据前序序列,我们知道左分支的头节点 为 pre[1],但它也出现在后序序列的左分支的最后。所以 pre[1] = post[L-1](因为结点的值具有唯一性),因此 L = post.indexOf(pre[1]) + 1。
- 递归由左子树的前序序列和后序序列建立左子树
- 递归由右子树的前序序列和后序序列建立右子树
综上可知,二叉树的重建关键在于确定根节点和左右分支,一旦这些确定了,那么即可用递归重建此二叉树。