如题:
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
这道题明显是有套路的,如果你还不会,说明你是第一次遇到,还好现在遇到,省的笔试的时候现场尴尬。可以根据中序遍历和后序遍历得到的序列递归求解子树。首先,我们知道,后序遍历得到的序列从后往前依次是原二叉树的根节点,根节点右子树的根节点.....,右子树的左子树的根节点。如果不理解的话, 没关系,待会看幅图就理解了。其次呢,我们可以知道,中序遍历中,根节点的位置是在中间的。这样,第一次,我们从后序遍历中找到根节点的值val,然后在中序遍历中找到val所属下标i,这时候得到val的左子树范围为【0, i-1】,右子树范围为【i+1, end】。紧接着,我们继续在相应的子树范围内找根节点,谁的根节点,分别是右子树的根节点和左子树的根节点,找到后,和val组合即可。看下图:
从图中的后序遍历从后往前观察,20是根节点,18是20右子树的根节点,7是18右子树的根节点。8是18的左子树根节点。像这样每次递归的查找根节点,然后组合即可。初始遍历的时候,中序遍历范围为0~InEnd,找到第一次后,划分为左子树范围【0, i-1】,右子树范围【i+1, end】。每次遍历从后序遍历数列中取根节点前,先判断其实范围start是否大于end,如果是的话,说明已经到底了,这时候递归即可返回。这一点结合代码可以看出:
struct TreeNode *findSubTree(int* inorder, int* postorder, int *postEnd, int inStart, int inEnd)
{
int val, i;
struct TreeNode *root, *left, *right;
//首先判断是否溢出了,溢出则返回。
if (inStart > inEnd)
return NULL;
//取出子树根节点
val = postorder[*postEnd];
//指针指向下一个子树的根节点
*postEnd = *postEnd - 1;
//中序遍历查找根节点所在位置
for (i = 0; i <= inEnd; i++)
if (inorder[i] == val)
break;
//在划分后的范围内继续查找root的右子树和左子树,顺序不能搞错
right = findSubTree(inorder, postorder, postEnd, i + 1, inEnd);
left = findSubTree(inorder, postorder, postEnd, inStart, i - 1);
//组合子树
root = (struct TreeNode *)calloc(1, sizeof(struct TreeNode));
root->val = val;
root->left = left;
root->right = right;
return root;
}
struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize){
//第一个根节点位置
int postEnd = postorderSize - 1;
//第一次查找,中序范围为0~inorderSize - 1。
return findSubTree(inorder, postorder, &postEnd, 0, inorderSize - 1);
}
参考资料:
1. 106. 从中序与后序遍历序列构造二叉树_哔哩哔哩 (゜-゜)つロ 干杯~-
https://www.bilibili.com/video/av45393236
=============================================================================================
Linux应用程序、内核、驱动、后台开发交流讨论群(745510310),感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。