L2-011 玩转二叉树 (25 分)
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N
(≤30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
1 2 3 4 5 6 7
4 1 3 2 6 5 7
输出样例:
4 6 1 7 5 3 2
这一题不知道二叉树便利顺序的可以先自行百度下或者看数据结构的书,自己理解下然后再搞会提高很多;
这一题就是给你中序遍历和前序遍历,让你求层序遍历,(先遍历右孩子再遍历左孩子就好了)
我们知道,如果知道中序遍历加上前序遍历与后序遍历中的一个就可以建出二叉树。
比如这一题。
1 2 3 4 5 6 7
4 1 3 2 6 5 7
根据前序遍历的性质,4为根节点。
然后找到中序遍历中4的位置,4左边的即左子树,右边的右子树。
然后看左子树,前序遍历中1 3 2对应的是左子树,所以1即左子树的根节点,
再找到1在中序遍历的位置,1左边的左子树(没有的话说明是空子树,令其结点值为-1.在我们的递归函数中l>r的情况就是这种情况)
/*
这里有个比较巧妙的地方,就是在前序遍历中,我们在递归函数中只需让pos++就能做到每次的根节点刚好是递归到的子树的根节点,因为前序遍历的顺序就是先根节点,再左子树,最后右子树,跟我们递归函数的顺序是一样的。
*/
以此类推,就重建出二叉树,最后BFS搜一下就行了,(记得先搜有孩子,再搜左孩子)。
#include<bits/stdc++.h>
using namespace std;
const int M = 111111;
int midt[M];
int pret[M];
int dt[M];
int pos = 1,n;
queue<int>q;
void rebuild(int l,int r,int rt)
{
// printf("%d %d %d %d\n",l,r,rt,pret[pos]);
if(l>r)//子树为空的情况
{
dt[rt]=-1;
return ;
}
int root=pret[pos++];//这里pos++就能做到在前序遍历中找到对应的根节点
dt[rt]=root;
int m=find(midt+l,midt+1+r,root)-(midt+1)+1;
rebuild(l,m-1,rt<<1); //重建左子树 ,不包括中点(根节点)。
rebuild(m+1,r,rt<<1|1); //重建右子树
}
void bfs()
{
int rt=1;
q.push(rt);
while(q.size())
{
int now=q.front();
q.pop();
if(dt[now]!=-1) //二叉树的叶子节点都是-1,所以不会无限BFS下去
{
if(now!=1)
cout<<" ";
cout<<dt[now];
q.push(now<<1|1); //先把右子树加入队列
q.push(now<<1); //再把左子树加入队列
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>midt[i];
for(int i=1;i<=n;i++)
cin>>pret[i];
rebuild(1,n,1);
bfs();
puts("");
return 0;
}