携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第41天,点击查看活动详情 >>
基于中序、后序遍历数组的递归法构建二叉树
今天我们来学习一种新的知识点,那就是如何通过递归方法构建基于中序遍历数组,后序遍历数组的二叉树的。
话不多说,我们马上进入正题:
题目分析
对于给定的两个数组(一个数组是二叉树的中序遍历结果,一个是二叉树后序遍历的结果,注意两个数组都是针对同一个二叉树的),利用这两个给定的数组进行二叉树构建。
其实就是想让我们通过中序遍历和后序遍历的两个数组,来还原原来的二叉树。
算法分析
这道题是要求使用递归算法来实现的,所以有一点我们需要明白的是,我们在让函数不断递归的时候,实际上是中序遍历数组和后序遍历数组这两个数组范围的改变。
每次递归时传入的范围都不一样。
其实这个递归构建也是有一定顺序的,下面展示的代码是按照前序遍历的顺序一步步去构建二叉树的。
算法代码的具体实现:
下面的是递归调用函数:
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (postorder.length == 0) {
return null;
}
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i); // 中序序列从数组变为map
}
//这里一共是六个参数,前三个参数是后序序列,后三个参数是中序序列
return buildTree(postorder, 0, postorder.length - 1, map, 0, inorder.length - 1);
}
递归终止条件:
// 递归终止条件:该范围的二叉树已经构建完毕
if (postEnd < postStart || inEnd < inStart) {
return null;
}
下面的是递归函数的具体实现:
private TreeNode buildTree(int[] postorder, int postStart, int postEnd, Map<Integer, Integer> map, int inStart, int inEnd) {
// 递归终止条件
if (postEnd < postStart || inEnd < inStart) {
return null;
}
/**
* 构建结点,注意在整棵树来看的话,这里构造的结点可不是只有根节点
* 其实二叉树的所有节点都是由它构建而来
* 也就是说 postEnd 并不是只是从后序遍历的数组的最后一个一个地往前
* 在需要构建左节点,或者右节点的时候, postEnd 所指的就是对应左节点或者右节点的下标
*/
TreeNode node = new TreeNode(postorder[postEnd]);
// 中序遍历中根节点的下标
int i = map.get(postorder[postEnd]);
// 由根节点分割出来的左子树的长度
int leftlen = i - inStart;
/**
* postStart + leftlen - 1 :表示左节点在后序遍历数组中的下标
* 【instart,i - 1】表示中序遍历数组中由根节点分割出来左边子树的范围
*/
node.left = buildTree(postorder, postStart, postStart + leftlen - 1, map, inStart, i - 1);
/**
* 【postStart + leftlen, postEnd - 1】表示的是处理了刚刚的结点之后,现在后序遍历中还没处理的结点数组
* (即去除了根节点,上面处理的左子树)
* 【i + 1, inEnd】 表示中序遍历数组中由根节点分割出来的右边的部分
*/
node.right = buildTree(postorder, postStart + leftlen, postEnd - 1, map, i + 1, inEnd);
return node;
}
总结:
下面我们一起来总结一下:
其实这道题的主要问题就存在于如何将中序遍历的数组和后序遍历的数组进行分割(要符合构建二叉树的要求) 从后序遍历数组的最后一个结点开始,它就是根节点 找到了根节点就可以在中序遍历的数组中划分左右子树了(注意这里的划分只是区分出了根节点左右子树的的组成结点(顺序不一定按顺序) 中序遍历数组{【左子树】, 根, 【右子树】} 后序遍历数组{【左子树】, 【右子树】, 根} 通过上面可以发现: 我们只需要在中序遍历的数组中统计了左子树的长度,其实它的长度是和后序遍历数组中的长度是一样的(元素组成的整体位置也是一样的,只不过顺序不同) 在中序遍历的数组中统计了右子树的长度,由它再加上左子树的长度开始处理就可以在后序遍历数组中找到右子树的位置 其实这里的递归不是根节点的递归而是后序遍历数组和中序遍历数组的递归,这两个数组都是通过两个变量来划定新的数组范围再进行递归 后序遍历数组:找根节点-》找根节点下面的根节点 - 》找根节点下面的根节点的根节点