我们无法根据树的先序遍历和树的后序遍历得到二叉树的结构,或者说结构是不确定的
单向陷门函数思想
hash函数的功能就是将某个大集合映射到小集合中,例如布隆过滤器或者布谷鸟过滤器。或者我们的一些密码的存储,并不是在数据库中直接放入我们的密码,这样如果数据库被盗或者丢失会造成很严重的损失。那么数据库上存储的密码实际上是我们密码的hash映射或某种加密下的密文。
既然是单向的就说明我们无法从以映射的集合得到原集合。同时这种压缩是有损的。
因此一棵树也可以看做是一个哈希映射。我们将含有n个节点的二叉树映射成为串长为n的一个字符串。那么你可能说,这不是没有损失节点吗?
千万别忘了,当二叉树用链表表示的时候,含有n个节点的二叉链表有n+1个空链域,就是二叉树中叶子节点指向的空指针。
因此当根据某个序列还原二叉树就会有很大的不确定性。
但是有个特殊的例子:只给出先序遍历和后序遍历无法还原出确定性的二叉树来
根据序列分析
我们可以看到当给定中序遍历的时候和任意后序或前序遍历时,我们可以很容易的把根节点找到。
比如分别有前序遍历和中序遍历:12463578和26417583
我们可以很容易的就可以根据先序遍历确定1为根节点,接着在中序遍历中找到1。1左边的就是左子树,右边的是右子树。
递归上述过程可以很容易就得出来完整且唯一的二叉树
———————————————————————————————————————————————————————————————————————————————————————————————————
但是如果我给定一个先序遍历序列和后序遍历序列:ABDE和DBEA
我们只能知道根节点是A,而对剩下的结构无法肯定。
因为我们观察后序遍历可以看到D是第一个被遍历的,这说明D必然为叶子节点。所以E肯定是A的有孩子
但是对于B和D我们无法肯定,我们唯一能确定的就是B是D的父亲节点
所以对于上述两个序列有两种可能:
————————————————————————————————————————————————————————————
代码实现
定义树的结构.h文件
#ifndef CONSTRUCT_H_
#define CONSTRUCT_H_
struct BTree
{
int val;
BTree *left;
BTree *right;
BTree(int x):val(x),left(nullptr),right(nullptr){}
};
#endif // CONSTRUCT_H_
主体结构
#include<iostream>
#include"define_tree.h"
#include<vector>
using namespace std;
//返回根节点在中序遍历中的位置
int get_index(int *obj,int a,int length) {
for (int i = 0;i < length- 1;i++) {
if (obj[i]==a) {
return i;
}
}
}
//根据前序和中序还原二叉树
BTree *build_tree_bypre(int *pre,int *mid,int length) {
//递归终止条件
if (length<=0) {
return 0;
}
BTree *root = new BTree(pre[0]);
int index = get_index(mid,root->val,length);
root->left=build_tree_bypre(pre+1,mid,index);
root->right = build_tree_bypre(pre+index+1,mid+index+1,length-index-1);
return root;
}
//根据中序和后序还原二叉树
BTree *build_tree_bybac(int *bac, int *mid,int length) {
//递归终止条件
if (length <= 0) {
return 0;
}
BTree *root = new BTree(bac[length-1]);
int index = get_index(mid,root->val,length);
root->left = build_tree_bybac(bac,mid,index);
root->right = build_tree_bybac(bac+index,mid+index+1,length-index-1);
return root;
}
//中序遍历二叉树
void mid_order(BTree *root) {
if (root==nullptr) {
return ;
}
mid_order(root->left);
cout << root->val << " ";
mid_order(root->right);
}
int main() {
int pre[] = {4,1,3,2,6,5,7};
int mid[] = {1,2,3,4,5,6,7};
int back[] = {2,3,1,5,7,6,4};
int length = 7;
mid_order(build_tree_bybac(back, mid, length));
cout << endl;
mid_order(build_tree_bypre(pre, mid, length));
system("pause");
return 0;
}