title: 根据先序遍历和中序遍历建立二叉树 date: 2019-07-23 22:37:34 tags: 数据结构
问题
已知一棵二叉树的先序遍历以及中序遍历,重建二叉树。二叉树的每一个节点有三个属性,左子节点,右子节点,以及节点值。
思路
先序遍历服从规则“根左右”,所以由此可知,对于一个先序遍历得到的数组,第一个元素一定是根节点;
中序遍历服从规则”左根右“,所以由此可知,对于一个中序遍历得到的数组,根节点左边的元素都属于根节点的左子树,而根节点右边的元素都属于根节点的右子树;
所以,我们可以先通过先序遍历的第一个元素确定根节点,然后通过中序遍历结合根节点,获得当前根节点的左右子树,再将子树看成一棵独立的树,继续使用先序遍历判断根节点,中序遍历判断子树的方式,最终建立起整棵树;
例子
假设有一棵二叉树,先序遍历为{1,2,4,7,3,5,6,8},中序遍历为{4,7,2,1,5,3,8,6},则建树过程如下:
首先,通过先序遍历可知树的根节点为1,则在中序遍历中,1左边的元素4,7,2即为根的左子树的元素,而1右边的元素5,3,8,6即为根节点的右子树;
对于左子树4,7,2来说,在先序遍历中,这三个点的顺序为2,4,7,则2为根节点,而在中序遍历中,4,7均在2的左边,则4,7均为以2为根树的左子树,且没有右子树;
对于4,7这两个节点来说,先序遍历中,4节点在7节点之前,所以4为根节点,而7作为子树,在中序遍历中,7在4之后,所以7为右子树;
对于根节点1的右子树5,3,8,6来说,在先序遍历中,3在最前面,所以3为这棵子树的根节点,而在中序遍历中,5在3的左边,所以属于左子树,而8,6在3的右边,属于右子树;
对于根节点3的右子树8,6,在先序遍历中,6在8之前,所以,6又为根节点,而在中序遍历中,8在6的左边,所以8是6的左子节点;
代码
树的节点
1 public class TreeNode { 2 int val; //当前节点的值 3 TreeNode left; //左子节点 4 TreeNode right; //右子节点 5 6 TreeNode(int x) { 7 val = x; 8 } 9 }
建树方法
1 /** 2 * pre:线序遍历得到的数组 3 * in:中序遍历得到的数组 4 */ 5 public TreeNode reConstructBinaryTree(int[] pre, int[] in) { 6 if(pre.length == 0) { 7 return null; 8 } 9 10 int root = pre[0]; 11 TreeNode node = new TreeNode(root); 12 13 //寻找根节点在in中的索引 14 int i = 0; 15 for( ; ii) { 16 if(in[i] == root) { 17 break; 18 } 19 } 20 21 //建立左子树 22 int[] leftIn = Arrays.copyOfRange(in, 0, i); 23 int[] leftPre = Arrays.copyOfRange(pre, 1, i+1); 24 node.left = reConstructBinaryTree(leftPre, leftIn); 25 26 //建立右子树 27 int[] rightIn = Arrays.copyOfRange(in, i+1, in.length); 28 int[] rightPre = Arrays.copyOfRange(pre, i+1, pre.length); 29 node.right = reConstructBinaryTree(rightPre, rightIn); 30 31 return node; 32 }
建树代码(优化)
1 public TreeNode reConstructBinaryTree(int[] pre, int[] in) { 2 return getRootTreeNode(pre, 0, pre.length-1, in, 0, in.length-1); 3 } 4 5 /** 6 * preL:当前子树在先序遍历的数组中的起始下标 7 * preR:当前子树在先序遍历的数组中的结束下标 8 * inL:当前子树在中序遍历的数组中的起始下标 9 * inR:当前子树在中序遍历的数组中的起始下标 10 */ 11 public TreeNode getRootTreeNode(int[] pre, int preL, 12 int preR, int[] in, int inL, int inR) { 13 if(preL > preR) { 14 return null; 15 } 16 17 TreeNode node = new TreeNode(pre[preL]); 18 19 for(int i=inL; i<=inR; ++i) { 20 if(in[i] == pre[preL]) { 21 22 node.left = getRootTreeNode(pre, preL+1, preL+i-inL, in, inL, i-1); 23 node.right = getRootTreeNode(pre, preL+i-inL+1, preR, in, i+1, inR); 24 break; 25 } 26 } 27 28 return node; 29 }