一、概述
根据前序和后序遍历,判断二叉树是否唯一。
乍一看有点懵,怎么判断呢?还是要上手模拟一下。
前序遍历结构:根节点、左子树、右子树
后序遍历结构:左子树、右子树、根节点
假设两个树都不空,那么是可以唯一确定一棵树的:通过前序确定左子树的根,后序确定右子树的根,然后分别遍历,可以将两个遍历各分为三部分。
那什么时候不能确定呢?在有一颗子树为空时不能确定,即一个节点它既是左子树的根又是右子树的根。这样两个都可以,就无法确定了。知道了这一点,就可以开始着手做了。
二、分析
我发现我这次用一种很奇怪的方式去建树。又不使用引用又不使用返回值。这很蛋疼。通常的方法这两个必须至少占其一的。代码看起来也容易晕。先来看看吧:
void create(int lpre,int rpre,int lpost,int rpost,Node* root)
{
if(lpre>=rpre||lpost>=rpost)
return;
/*if(lpre==rpre||lpost==rpost)
{
Node* leaf=new Node;
leaf->data=lroot;
leaf->lchild=NULL;
leaf->rchild=NULL;
root=leaf;
}*/
int lroot=pre[lpre+1];
int rroot=post[rpost-1];
if(lroot==rroot)
{
uniquetree=0;
Node* leaf=new Node;
leaf->data=lroot;
leaf->lchild=NULL;
leaf->rchild=NULL;
root->lchild=leaf;
create(lpre+1,rpre,lpost,rpost-1,root->lchild);//当做左根,只建左子树
}
else
{
int lrootinpost=-1;
for(int i=0;i<N;i++)
{
if(post[i]==lroot)
{
lrootinpost=i;
break;
}
}
int rrootinpre=-1;
for(int i=0;i<N;i++)
{
if(pre[i]==rroot)
{
rrootinpre=i;
break;
}
}
int ltreenum=rrootinpre-lpre-1;
int rtreenum=rpost-lrootinpost-1;
Node* lleaf=new Node;
lleaf->data=lroot;
lleaf->lchild=NULL;
lleaf->rchild=NULL;
root->lchild=lleaf;
Node* rleaf=new Node;
rleaf->data=rroot;
rleaf->lchild=NULL;
rleaf->rchild=NULL;
root->rchild=rleaf;
create(lpre+1,rrootinpre-1,lrootinpost-ltreenum+1,lrootinpost,root->lchild);
create(rrootinpre,rrootinpre+rtreenum-1,lrootinpost+1,rpost-1,root->rchild);
}
}
看了代码之后我才明白为什么我不用引用了。用引用是为了不出现值传递导致根节点没法初始化,我这个是先初始化完了,在一个以存在的,弄好的节点上给他加左右子树,运行一次加两个。这样一来就不能用平时的方法了。
平时是我知道有一个空节点,我去建一个把它填上;
这个是我有一个节点,去给它加左右子树,细究起来与插入法建树有点像。
由于一次加两个节点,因此左等于右的时候也要返回,只有一个显然不够。
因此对于建树类题目,在设计建树算法时,首先要想明白,我是给一个空节点赋值,还是往实节点下面添节点。这点想明白了函数也就好写了。
在建树的时候就可以判断是否唯一了,不唯一可以默认是左子树,然后插进去继续做就行。
三、总结
又是一道建树的题目。建树的小坑可真不少。
PS:代码如下:
#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
//前序遍历和后序遍历,前序遍历可得根,假设根后面的是左子树的根
//后序遍历可得根,假设根前面的是右子树的根
//如果这两个不相等,说明唯一
//如果相等,令其为左子树的根,右子树不存在
int pre[35],post[35];
struct Node
{
int data;
Node* lchild;
Node* rchild;
};
int uniquetree=1;
Node* root=new Node;
int N;
void create(int lpre,int rpre,int lpost,int rpost,Node* root)
{
if(lpre>=rpre||lpost>=rpost)
return;
/*if(lpre==rpre||lpost==rpost)
{
Node* leaf=new Node;
leaf->data=lroot;
leaf->lchild=NULL;
leaf->rchild=NULL;
root=leaf;
}*/
int lroot=pre[lpre+1];
int rroot=post[rpost-1];
if(lroot==rroot)
{
uniquetree=0;
Node* leaf=new Node;
leaf->data=lroot;
leaf->lchild=NULL;
leaf->rchild=NULL;
root->lchild=leaf;
create(lpre+1,rpre,lpost,rpost-1,root->lchild);//当做左根,只建左子树
}
else
{
int lrootinpost=-1;
for(int i=0;i<N;i++)
{
if(post[i]==lroot)
{
lrootinpost=i;
break;
}
}
int rrootinpre=-1;
for(int i=0;i<N;i++)
{
if(pre[i]==rroot)
{
rrootinpre=i;
break;
}
}
int ltreenum=rrootinpre-lpre-1;
int rtreenum=rpost-lrootinpost-1;
Node* lleaf=new Node;
lleaf->data=lroot;
lleaf->lchild=NULL;
lleaf->rchild=NULL;
root->lchild=lleaf;
Node* rleaf=new Node;
rleaf->data=rroot;
rleaf->lchild=NULL;
rleaf->rchild=NULL;
root->rchild=rleaf;
create(lpre+1,rrootinpre-1,lrootinpost-ltreenum+1,lrootinpost,root->lchild);
create(rrootinpre,rrootinpre+rtreenum-1,lrootinpost+1,rpost-1,root->rchild);
}
}
int nodenum=0;
void inorder(Node* root)
{
if(root->lchild!=NULL)
inorder(root->lchild);
printf("%d",root->data);
nodenum++;
if(nodenum<N)
printf(" ");
if(root->rchild!=NULL)
inorder(root->rchild);
}
int main()
{
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&pre[i]);
for(int i=0;i<N;i++)
scanf("%d",&post[i]);
root->data=pre[0];
root->lchild=NULL;
root->rchild=NULL;
create(0,N-1,0,N-1,root);
if(uniquetree==1)
{
printf("Yes\n");
inorder(root);
printf("\n");
}
else
{
printf("No\n");
inorder(root);
printf("\n");
}
}