刚做了华为OJ练习,华为中给出了重建二叉树这道题目:
要求,给出前序和中序遍历,要求如果能够重建二叉树,就输出二叉树的后序遍历,否则的话输出"No"
重建二叉树一定要深刻理解二叉树的遍历(前、中、后)
#include<iostream>
using namespace std;
int n;
int a[1005]; //记录前序遍历的结果
int b[1005]; //记录中序遍历的结果
int c[1005][1005]; //用于记录中序遍历中,c[i][j]表示i是在j的左子树还是右子树
int L[1005]; //记录后序遍历的结果
int pL=0;//当前L元素位置
int F[1005]; //记录重建二叉树后前序遍历的结果
int pf=0;//当前F元素位置
int Z[1005]; //记录重建二叉树中序遍历的结果
int pz=0;//当前Z元素位置
struct node{
//left表示左子树、right表示右子树
node *left,*right;
int value;
};
node *head;//表示头,根节点
//这是用来求L的
void printL(node *f){
F[pf++]=f->value; //在左右递归之前记录value,这是前序遍历,父、左、右
if(f->left!=NULL) printL(f->left); //向左子树递归
Z[pz++]= f->value;//左、中、右,先遍历左子树,直接递归到叶节点,然后回溯记录,中序遍历
if(f->right!=NULL) printL(f->right);//向右子树递归
L[pL++]=f->value;//左、右、中,先遍历左子树,后右子树,后父节点,后序遍历
}
int main(){
while(cin>>n){
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++) {
cin>>b[i];
for(int j=0;j<i;j++){
c[b[j]][b[i]]=1; //b[j]节点在b[i]节点之前,即在其左边
c[b[i]][b[j]]=-1;
}
}
head = (struct node *)malloc(sizeof(node));
head->value=a[0];//头结点
head->left=NULL;
head->right=NULL;
for(int i=1;i<n;i++){
//以前序遍历为基础,中序遍历为控制条件,重建二叉树
node *fn= (struct node *)malloc(sizeof(node));
fn->left=NULL;
fn->right=NULL;
fn->value=a[i];
node *h=head;
node *ph=head;
int flag=0;
while(h!=NULL){
ph=h;
if(c[fn->value][h->value] == 1) //向左递归
{
h=h->left;
if(h==NULL) ph->left=fn; //递归到叶节点,结束,添加fn
}
else if(c[fn->value][h->value] == -1)//向右递归
{
h=h->right;
if(h==NULL) ph->right=fn;//递归到叶节点,结束,添加fn
}
}
}
pL=0;
pf=0;
pz=0;
printL(head);//求重建后的二叉树,前、中、后
int flag=0;
//判断重建后的二叉树,前后遍历顺序是否正确,错误,则无法重建二叉树
for(int i=0;i<n;i++){
if(a[i]!=F[i]) {
flag=1;
break;
}
if(b[i]!=Z[i]){
flag=1;
break;
}
}
if(flag==0){
for(int i=0;i<n;i++)
cout<<L[i]<<" ";
cout<<endl;
//cout<<L[n-1]<<endl;
}
else cout<<"No"<<endl;
}
return 0;
}