看了下面文章后的感悟:
https://blog.csdn.net/destiny_balabala/article/details/99352715
举例:
前序:1、2、5、3、4
后序:5、4、3、2、1
二叉树不唯一原因:
前序:NLR
后序:LRN
光看序列数字是看不出来位置的,要看相对位置
例如前序与中序:LNR,由前序的N,可以在中序找到相对于N左边为左子树
本题在后序中找到N,但是N前面是LR,二叉树可能只有左子树,只有右子树,或都有,因此后序中N前面的是L还是R不可知,由此造成了二叉树不唯一
二叉树不唯一的判断:
在王道书的P146,T9,如果二叉树只有一个叶子结点,则前序与后序遍历序列相反
由此我们可以找出前序中的N1,以及下一个L1,然后在后序中找到对应的N1前面一个元素R2,若R2=L1,至少在该子树里前后序为逆序,说明只有一个叶子结点,但是不知道是左还是右,所以此处不唯一;
例如:前序的N1=1,L1=2
后序中找到N1的位置,前一个元素R2=2=L1,局部逆序,说明2可能是1的左子树或右子树
如果R2!=L1,说明在以N1为根结点的局部子树中,有左孩子和右孩子,此处唯一
二叉树局部唯一后如何判断左右子树:
由后序的LRN,L1和N1之间都是右子树,L1以及之前的都是左子树(L除非是叶结点,否则L还可分为LRN(递归体),自然不会只有L1这一个元素)
所以此处可以作为递归点
找到左子树区间,右子树区间,再由该区间的的前序后序,递归找出左右子树
#include<bits/stdc++.h>
using namespace std;
int pre[40],post[40],n;
bool uni=true;
vector<int> v;
struct node{
int data;
node *left=NULL,*right=NULL;
};
void create_tree(node* &root,int l1,int l2,int len){
if(len==0) //两个递归出口
return;
root= new node;
root->data=pre[l1];
if(len==1)return; //只有一个根结点,不用再对左右子树进行处理
int i;
for(i=l2;i<l2+len;i++){ //找左右子树区间
if(post[i]==pre[l1+1])
break;
}
int leftlen,rightlen;
leftlen=i-l2+1;
rightlen=len-leftlen-1; //减一是pre[l1]为根
if(rightlen==0) //之间没有元素,说明只有一棵子树
uni=false;
create_tree(root->left,l1+1,l2,leftlen); //如果只有一个结点默认判为左子树
create_tree(root->right,l1+1+leftlen,i+1,rightlen);
}
void inordertraverse(node* p){
if(p){
inordertraverse(p->left);
v.push_back(p->data);
inordertraverse(p->right);
}
}
int main(){
cin>>n;
for(int i=0;i<n;i++)
cin>>pre[i];
for(int i=0;i<n;i++)
cin>>post[i];
node* root=NULL;
create_tree(root,0,0,n);
inordertraverse(root);
if(uni==true) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
for(int i=0;i<v.size();i++)
{
if(i!=0)
cout<<" ";
cout<<v[i];
}
cout<<endl;
return 0;
}