1. 问题描述:
已知二叉树节点按先序遍历下的序列存储在一维数组pre[l1, ....r1]中,按中序遍历下的序列存储在一维数组中in[l2, ...r2]中,其中l1,r1,l2,r2指示了数组中元素(类型为char型)存储的下标范围,假定二叉树中节点的值互不相同,试写出由pre[l1...r1]和in[l2,...r2]构造出二叉树的算法。
2. 思路分析:
① 我们根据二叉树遍历的性质可以知道先序遍历和中序遍历二叉树是可以唯一确定一棵二叉树的,中序遍历和后序遍历也是可以唯一确定一棵二叉树的,只有先序遍历和后序遍历不可以确定一棵二叉树,举个例子:当二叉树是单分支结构的时候此时二叉树的先序遍历与后续遍历恰好是逆序的关系,此时前序遍历与后序遍历中的节点可以是左孩子也可以是右孩子,所以不能够唯一确定一棵二叉树。
② 根据题目我们已知先序遍历序列和中序遍历序列那么我们可以根据先序遍历来确定根,然后在中序遍历中找到根所以这样就可以确定了根的左子树的范围和右子树的范围。
再对左子树和右子树进行相同的方法进行处理,因为处理的方法都是一样的所以我们可以使用递归解决。
③ 在递归的方法中我们需要确定先序遍历序列和中序遍历中的当前的左右子树的范围,我们可以举出下面的具体的例子来帮助我们理解:
先序遍历顺序为:1 2 5 3 4
中序遍历顺序为:5 2 3 1 4
1)先序遍历中第一个是根那么在中序遍历中找到根那么左右子树就确定了,所以自然左右子树的范围就确定了,所以在递归方法中先序遍历的左子树的边界范围是l1 + 1, l1 + i - l2。
因为第一个是根所以下一次递归的时候应该是下一个位置,但是左子树应该在什么位置结束呢?我们可以通过中序遍历中左子树的范围进行确定,可以结合上面的例子进行理解,可以知道左子树的范围为l1 + (i - l2)。
也可以这样想设先序遍历左子树结束位置为x,则x + 1- (l1 + 1) = i - l2,所以可以得到左子树的结束范围是 l1 + (i - l2),对于中序遍历序列中当前左子树的范围应该是l2, i - 1(i为根所在的位置)。
2)对于右子树来说,我们知道先序遍历的范围的起点应该是在先序遍历左子树结束位置上加1的位置,结束位置是在r1, 中序遍历中右子树的范围应该是i + 1, r2
我们可以模仿之前的递归创建完全二叉树的例子,可以将根节点的左指针指向递归创建的左子树,根节点的右指针指向递归创建的右子树即可。
3)核心是其中的递归方法中参数的确定。
3. 代码如下:
3
9 20
1 6 15 7
45 67 4
public class Main {
public static void main(String[] args) {
int pre[] = {3, 9, 1, 45, 67, 6, 20, 15, 4, 7};
int in[] = {45, 1, 67, 9, 6, 3, 4, 15, 20, 7};
TreeNode<Integer> root = createTree(pre, in, 0, 9, 0, 9);
System.out.print("先序遍历的顺序是: ");
preOrder(root);
System.out.println();
System.out.print("中序遍历的顺序是: ");
inOrder(root);
System.out.println();
System.out.print("后序遍历的顺序是: ");
lastOrder(root);
}
private static void preOrder(TreeNode<Integer> node) {
if(node == null) return;
System.out.print(node.value + " ");
preOrder(node.left);
preOrder(node.right);
}
private static void inOrder(TreeNode<Integer> node) {
if(node == null) return;
inOrder(node.left);
System.out.print(node.value + " ");
inOrder(node.right);
}
private static void lastOrder(TreeNode<Integer> node) {
if(node == null) return;
lastOrder(node.left);
lastOrder(node.right);
System.out.print(node.value + " ");
}
private static TreeNode<Integer> createTree(int[] pre, int[] in, int l1, int r1, int l2, int r2) {
if(l1 > r1) return null;
int i = 0;
for(i = l2; i < r2; i++){
if(in[i] == pre[l1]) break;
}
TreeNode<Integer> s = new TreeNode<Integer>(in[i]);
s.left = createTree(pre, in, l1 + 1, l1 + i - l2, l2, i - 1);
s.right = createTree(pre, in, l1 + i - l2 + 1, r1, i + 1, r2);
return s;
}
public static class TreeNode<T>{
TreeNode<T> left;
TreeNode<T> right;
T value;
public TreeNode(T value) {
super();
this.value = value;
}
}
}