虽然说了解到先序和后序确定唯一二叉树的条件是不能有节点只有左子树或者又子树,这点是很好论证的,先序是根左右,后序是左右根,因此如果只有某个子树的话就不能确定他是左子树还是右子树了。
那么该如何在代码上实现呢,这里可以从build这个函数的k中说起,这里k从pre的先序左子树开始,一直找到等于post[por-1]的位置为止,post[por-1]位于当前树的右子树的根节点,那么对于在pre找到的k位置来说,找到的也是右子树的根节点,这个看起来像这样:
根。。。 . 。。 (先序)
。。。 。。 . 根(后序)
其中 . 代表k的位置。
那么如果k-prl>1,这说明左子树的长度不为0,而k又是位于右子树的,这样就说明目前既有左子树,又有右子树(那么为什么是k-prl>1而不是>0呢,因为相邻的两个数相减就是1,而这时表示中间没有数字可以当子树了,这点我也想了好久),总之,满足这个条件,就表示左右子树双全,那么暂时可以确定一棵二叉树。
之后,要是发现不符合的点,就统一往右子树插好了
还有一点需要注意的是,判断是否唯一的flag时,k-prl>1其实不能算是唯一的条件,还需要判断我们建树建到这里时,子树的长度是不是等于1了,这其实是一种唯一的情况,但按照我们给的条件却会让flag置false,因此还需要加判断才可以。
#include <stdio.h>
#include <vector>
using namespace std;
struct node{
int data;
node* left;
node* right;
};
vector<int> pre,in,post;
bool flag=true;
node* build(int prl,int prr,int pol,int por){
if(prl>prr){
return NULL;
}
node* root=new node;
root->data=pre[prl];
root->left=NULL;
root->right=NULL;
if(prl==prr){
return root;
}
int k=prl+1;
for(;k<=prr;k++){
if(pre[k]==post[por-1]){
break;
}
}
if(k-prl>1){//有左子树
root->left=build(prl+1,k-1,pol,pol+k-prl-2);
root->right=build(k,prr,pol+k-prl-1,por-1);
}else{
flag=false;
root->right=build(k,prr,pol+k-prl-1,por-1);
}
return root;
}
void inorder(node* root){
if(root==NULL){
return;
}else{
inorder(root->left);
in.push_back(root->data);
inorder(root->right);
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
int temp;
scanf("%d",&temp);
pre.push_back(temp);
}
for(int i=0;i<n;i++){
int temp;
scanf("%d",&temp);
post.push_back(temp);
}
node* root=build(0,n-1,0,n-1);
inorder(root);
if(flag){
printf("Yes\n");
}else{
printf("No\n");
}
for(int i=0;i<in.size();i++){
printf("%d",in[i]);
if(i!=in.size()-1){
printf(" ");
}else{
printf("\n");
}
}
return 0;
}