前言
遇到这么一道题,现在知道二叉树前序遍历和后序遍历,如何通过这些信息来重构二叉树。
咋一看估计还有点懵,把数据拿出来细细一分析就知道,其实也还挺简单的。
算法思路
现在有如下数据:
前序遍历 : 3 2 1 5 4 8 7 9
中序遍历 : 1 2 3 4 5 7 8 9
根据前序遍历的规律我们知道,前序遍历的第一位数据是根节点的数据,OK我们把第一位数据标记出来:
前序遍历 : [3] 2 1 5 4 8 7 9
中序遍历 : 1 2 [3] 4 5 7 8 9
那么又根据遍历(前、中、后序遍历都一样)的规律,我们知道遍历总是先输出左子树,再输出右子树,区别仅在于根节点数据的位置不同(前、中、后)。那么在中序遍历中,根节点数据左边的必然是左子树的数据,右边的则是右子树的数据。我们根据这一点,可以把数据划分为根节点、左子树和右子树。
根节点 前序遍历 :3 中序遍历 : 3
左子树 前序遍历 :2 1 中序遍历 : 1 2
右子树 前序遍历 :5 4 8 7 9 中序遍历 : 4 5 7 8 9
OK,到了这一步以后,聪明的朋友应该知道怎么接着做了。把左子树和右子树递归执行上面一样的操作,直到所有数据都做了一次根节点,算法执行结束。
代码实现
//二叉树结构体
struct Tree {
int value;
Tree *left;
Tree *right;
};
//pre:前序遍历
//mid:中序遍历
//length:数组长度
Tree* Fun(const int *pre, const int *mid,const int length) {
//当空指针或者数组长度为0时返回
if (pre == NULL || mid == NULL || length <= 0)
return NULL;
//建立根节点
Tree *head = new Tree();
head->value=pre[0];
//找到中序遍历中根节点所在位置
int index = 0;
while (index<length) {
if (head->value == mid[index])
break;
++index;
}
//划分左子树
head->left = Fun(pre + 1, mid, index);
//划分右子树
head->right = Fun(pre + index +1, mid + index + 1, length - index - 1);
return head;
}
扩展
假如把前序遍历换成后序遍历又如何?思路还是一样,有兴趣的朋友可以自行探索。无聊的我把代码也丢这里了。
//mid:中序遍历
//back:后序遍历
//length:数组长度
Tree* Fun2(const int *mid,const int *back,const int length){
//当空指针或者数组长度为0时返回
if(back==NULL||mid==NULL||length<=0)
return NULL;
//建立根节点
Tree *head=new Tree();
head->val=back[length-1];
head->left=head->right=NULL;
//找到中序遍历中根节点所在位置
int index=0;
while(index<length){
if(head->val==mid[index]){
break;
}
++index;
}
//划分左子树
head->left=Fun2(mid,back,index);
//划分右子树
head->right=Fun2(mid+index+1, back+index, length-index-1);
return head;
}
如果没有中序遍历呢?靠前序遍历和后序遍历也能倒推出树吗?有兴趣的可以看我另一篇文章利用任意两种遍历方式重建二叉树。