Num7-重建二叉树
一、题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示的二叉树并输出它的头结点。
二、分析题目
1. 前序遍历的顺序 根左右
2. 中序遍历的顺序 左根右
3. 目标:还原一棵二叉树
4. 特殊值部分:输入为空的情况
三、方法
1.递归
由前序遍历的特点可知,对于前序遍历而言,第一个节点必定是根节点,类似的也可以得出后序遍历的最后一个节点是根节点
对于中序遍历比较特殊,因为中序遍历的顺序是: 左根右(先遍历左子树,再遍历根节点,最后遍历右子树),所以中序遍历无法单独判断序列中的第一个节点是根节点与否
所以需要借助先序遍历先确定根节点,然后在中序遍历序列中找到该节点,那么在该节点左边的就是属于左子树的节点,右侧的就是属于右子树的节点
借助书中的图片
伪代码:
//有先序序列 pre[]数组, 中序遍历序列 in[]数组
1. 在 pre[]中确定第一个元素 pre[0]
2. 在 in[] 中找到 pre[0] 的位置 i, 若没找到则抛出错误,若找到则创建 pre[0] 节点
3. 接下来在 in[] 的 0 ~ i-1 位置处找到 pre[1]
4. 在 in[] 的 i+1 ~ length-1 处寻找 pre[i+1]
代码如下:
//重建二叉树,先序遍历即中序
public static BiTreeNode CreateTree(int[] PreOrder, int[] InOrder){
if(PreOrder==null || InOrder==null || PreOrder.length!=InOrder.length)
return null;
return CreateTree(PreOrder,0, PreOrder.length-1, InOrder, 0, InOrder.length-1);
}
public static BiTreeNode CreateTree(int[] PreOrder,int ps, int pe, int[] InOrder, int is, int ie){
if(is>ie)
return null;
//创建新节点
BiTreeNode root = new BiTreeNode();
int i = 0;
while(PreOrder[ps]!=InOrder[i]&&i<=ie){
i++;
}
if(i > ie)
throw new RuntimeException("Invalid input");
// 为节点赋值,并且递归创建左、右子树
root.data = PreOrder[ps];
root.lChild = CreateTree(PreOrder, ps + 1, ps + i -is, InOrder, is, i-1);
root.rChild = CreateTree(PreOrder, ps + i - is + 1, pe, InOrder, i+1, ie);
return root;
}
创建二叉树类
package Base.Bitree;
import java.util.Stack;
public class BiTreeNode {
public int data;
public BiTreeNode lChild;
public BiTreeNode rChild;
public BiTreeNode father;
public BiTreeNode(int data){
this.data = data;
}
public BiTreeNode(){}
//先序遍历
public void PreOrder(BiTreeNode root){
if (root == null)
return;
System.out.println(root.data);
PreOrder(root.lChild);
PreOrder(root.rChild);
}
//先序非递归
public void PreOrder2(BiTreeNode root){
if(root==null)
return;
Stack<BiTreeNode> stack = new Stack<BiTreeNode>();
BiTreeNode p = root;
stack.push(p);
while(p!=null&&!stack.isEmpty()){
p = stack.pop();
System.out.println(p.data);
if (p.rChild!=null)
stack.push(p.rChild);
if(p.lChild!=null)
stack.push(p.lChild);
}
}
}
主函数
主函数中调用了先序遍历作为验证
public static void main(String[] args) {
int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
int[] in = {4, 7, 2, 1, 5, 3, 8, 6};
int length = pre.length;
BiTreeNode root;
root = CreateTree(pre, in);
root.PreOrder2(root);
}
总结
在该算法的过程中得注意,pre[ ] 与 in[ ] 的索引问题,在中序中找到根节点后,左、右子树的大小也就确定了,因此索引也得在正确范围内。
在二叉树问题中一般的方法是递归解决。