背景
根据提供的前序和中序遍历的结果,重构二叉树
思路
根据前序和中序的特点,来构造二叉树。
前序遍历,根左右,头一个一定是根结点。
中序遍历,左根右,根据由前序遍历确定的根结点,可以确定出左右子树的中序遍历结果,以及左右子树的元素数量。
而后,根据中序遍历确定的左右子树的元素数量,可以分出前序遍历中左右子树的范围。
最后,进行递归,后序遍历验之。
实现
代码如下
package practice;
import oo.MyTree;
public class RebuildBinaryTree {
public static void reBuild(MyTree t, int[] pre, int[] in) {
int leftLength = -1; // 左子树长度
int rightLength = -1; // 右子树长度
int rootData = pre[0]; // 先序遍历,第一个一定是根结点
t.setData(rootData);
for (int i = 0; i < in.length; i++) {
if (in[i] == rootData) {
leftLength = i;// leftLength = 3 1
break;
}
} // 中序遍历,根节点前面的都是左子树,据此求出左子树长度
if (leftLength <= 0) {
t.setLeft(null);
// 如果左子树长度小于1,说明中序遍历的头一个就是根结点,也就是没有左子树
} else {
// 否则,说明有左子树,把左子树的先序遍历和中序遍历的结果拷贝,进行递归构造
int[] leftInOrder = new int[leftLength];
int[] leftPreOrder = new int[leftLength];
for (int i = 0; i < leftLength; i++) {
leftInOrder[i] = in[i];
leftPreOrder[i] = pre[i + 1]; // i+1是因为先序遍历的第一个是根结点
}
t.setLeft(new MyTree());
reBuild(t.getLeft(), leftPreOrder, leftInOrder); // 递归
}
// 相似的方法构造右子树
if (leftLength == in.length - 1) {
t.setRight(null);
// 如果左子树的长度是中序遍历的结果-1,那左子树配上根结点,就是中序遍历的全部结果,也就是没有右子树了
} else {
rightLength = in.length - leftLength - 1;
// 否则,就是有右子树,其长度是中序长度-左子树长度-根结点(也就是-1)
// 这个右子树长度,也可以看成右子树元素在中序遍历结果中的偏移量
int[] rightInOrder = new int[rightLength];
int[] rightPreOrder = new int[rightLength];
for (int i = 0; i < rightLength; i++) {
rightInOrder[i] = in[i + rightLength]; // 拷贝时要加上偏移量
rightPreOrder[i] = pre[i + rightLength];
}
t.setRight(new MyTree());
reBuild(t.getRight(), rightPreOrder, rightInOrder); // 递归
}
}
public static void main(String[] args) {
// 前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
int[] pre = { 1, 2, 4, 7, 3, 5, 6, 8 };
int[] in = { 4, 7, 2, 1, 5, 3, 8, 6 };
MyTree t = new MyTree();
reBuild(t, pre, in);
t.travelsInLastOrder(); // 后序遍历验证结果
}
}
运行结果
由前序和中序可知树的拓扑图为
后序遍历的打印结果为
可见运行没问题。