二叉树中,可以根据前序遍历或者后序遍历配合中序遍历对二叉树进行还原,不使用中序则不能唯一确定一棵二叉树。
一、二叉树前中后遍历总结
前、中、后都是针对头节点来说的。
1.前序遍历:先遍历头节点。头->左->右
下图前序遍历结果:f->b->a->d->c->e->g->i->h
2.中序遍历:左->头->右
下图中序遍历结果:a b c d e f g h i
3.后序遍历:左->右->头
下图后序遍历结果:a c e d b h i g f
二、上面相信大家应该都可以遍历出来,那我们应该怎样将其还原出这颗唯一的二叉树呢?
1.前序+中序
思路:前序遍历的第一个节点一定是整棵树的头节点。同样,在中序中找到这个节点位置可以知道根节点左边的数组就是其左子树,右边就是右子树。前序左子树为对应根节点后面的和中序左子树长度相同数据,右子树在左子树后面。
带入例子中序中,实际就是前序第一个节点为f,是整棵树的头节点。f前面有五个数,是整棵树的左子树(abcde),f后面三个数为右子树(ghi)。前序中对应左子树为f后五个(badce),右子树为剩下三个(gih)。
实现代码:
#include
//类型定义
struct TreeNode
{
int val;
struct TreeNode* left;
struct TreeNode* right;
};
struct TreeNode* RebuildTree(int* preorder, int perSize, int* inorder, int inSize)
{
if (preorder == NULL || perSize == 0 || inorder == NULL || inSize == NULL)
return NULL;
struct TreeNode* root = malloc(sizeof(struct TreeNode));
root->val = preorder[0]; //前序第一个为头节点
int i = 0;
for (; i < inSize; i++) //找出头节点位于中序位置
{
if (inorder[i] == preorder[0])
break;
}
//递归重建
root->left = RebuildTree(&preorder[1],i,&inorder[0],i);
root->right = RebuildTree(&preorder[i+1],perSize-i-1,&inorder[i+1],inSize-i-1);
return root;
}
int main()
{
int preorder[5] = { 3,9,20,15,7 }; //先序
int inorder[5] = { 9,3,15,20,7 }; //中序
RebuildTree(preorder, 5, inorder, 5);
return 0;
}
上面的传参方法我觉得很妙,之前都没试过。果然还得是指针。
2.后序+中序
思路:类似前一种,实际后序遍历头节点是从最后开始的,中序同样分割,各位可以仔细思考一下。这里直接给出代码:
#include
struct TreeNode
{
int val;
struct TreeNode* left, * right;
};
struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize) {
if (inorder == NULL || postorder == NULL || inorderSize == 0 || postorderSize == 0)
return NULL;
struct TreeNode* root = malloc(sizeof(struct TreeNode));
root->val = postorder[postorderSize - 1];
printf("%d ", root->val);
int i = 0;
for (; i < inorderSize; i++)
{
if (inorder[i] ==root->val)
break;
}
//递归重建
root->left = buildTree(&inorder[0], i, &postorder[0], i);
root->right = buildTree(&inorder[i+1],inorderSize-i-1,&postorder[i],postorderSize-i-1);
return root;
}
int main()
{
int inorder[] = { 2,1,3 }; //中序
int postorder[] = { 2,3,1 };//后序
buildTree(inorder,3, postorder, 3);
return 0;
}
总结:其实二叉树的遍历都是有迹可循的,各种遍历差别不大。其次,指针和递归是在树这个知识点中最常用的知识点,需要有一定的基础。