L2-006 树的遍历 (25 分) (根据后序遍历与中序遍历建二叉树)

题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805069361299456

L2-006 树的遍历 (25 分)
 

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2


解题思路:首先我们根据后序遍历最后一个数可确定二叉树的根,然后再从中序遍历找到该节点便能确定该根节点左右子树的节点,举个例子拿样例来说:
初始时,我们根据后序遍历知道整棵树的根节点是4,于是我们便在中序遍历找到4的位置,我们就可以确定,节点1,2,3在根节点左子树,节点3,5,7,2在根节点右子树,于是我们又采用此方法,递归在后序遍历的区间【1,3】和中序遍历的区间【1,3】建立4的左子树,在后序遍历的区间【4,6】和中序遍历的区间【5,7】建立4的右子树就可以了。
具体方法看代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,post[35],mid[35];
struct node{
  int l,r;
}tree[55];
vector<int> ans;
int build(int l1,int r1,int l2,int r2){//l1,r1表示中序遍历的左右边间,l2,r2表示后序遍历的左右边界 
  if(l1>r1)return 0;  //递归结束条件即没有元素可以遍历 
  int p1,cnt,rt=post[r2];  //rt为当前子树的根节点 即为当前后序遍历的最后一个数 
  p1=l1;  //初始p1位中序遍历的左边界 
  while(mid[p1]!=rt)p1++; //在中序遍历中查找根节点所在位置 
  cnt=p1-l1; //计算当前根节点的子节点个数 
  tree[rt].l=build(l1,p1-1,l2,l2+cnt-1); //递归构建左子树 
  tree[rt].r=build(p1+1,r1,l2+cnt,r2-1); //递归构建右子树 
  return rt;
}
void bfs(int rt){  //bfs搜索层序遍历 
  queue<int> que;
  que.push(rt);
  ans.push_back(rt);
  while(que.size()){
    int u=que.front();
    que.pop();
    if(tree[u].l!=0){
      que.push(tree[u].l);
      ans.push_back(tree[u].l);
    }
    if(tree[u].r!=0){
      que.push(tree[u].r);
      ans.push_back(tree[u].r);
    }
  }
  for(int i=0;i<ans.size();i++){
    cout<<ans[i];
    if(i!=ans.size()-1)cout<<" ";
    else cout<<endl;
  }
}
int main(){
  cin>>n;
  for(int i=1;i<=n;i++)cin>>post[i];
  for(int i=1;i<=n;i++)cin>>mid[i];
  int root=build(1,n,1,n);
  bfs(root);
  return 0;
}

 

L2-011 玩转二叉树 (25 分)

题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805065406070784

给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数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


解题思路:和上题几乎是一样的,把后序改为先序,先序遍历的第一个元素就是根节点,知道这个就可以了。镜面反转只需要改变一下bfs的搜索方式就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,root,pre[35],mid[35];
struct node{
  int l,r;
}tree[55];
vector<int> ans;
int build(int l1,int r1,int l2,int r2){//l1,r1为中序遍历的左右边界,l2,r2为先序遍历的左右边界 
  if(l1>r1)return 0;
  int p,cnt,rt=pre[l2]; //先序遍历的第一个元素为当前树的树根 
  p=l1;
  while(mid[p]!=rt)p++;
  cnt=p-l1;
  tree[rt].l=build(l1,p-1,l2+1,l2+cnt);
  tree[rt].r=build(p+1,r1,l2+cnt+1,r2);
  return rt;
}
void bfs(int rt){
  queue<int> que;
  que.push(rt);
  ans.push_back(rt);
  while(que.size()){
    int u=que.front();
    que.pop();
    if(tree[u].r!=0){
      ans.push_back(tree[u].r);
      que.push(tree[u].r);
    }
    if(tree[u].l!=0){
      ans.push_back(tree[u].l);
      que.push(tree[u].l);
    }
  }
  for(int i=0;i<ans.size();i++){
    cout<<ans[i];
    if(i!=ans.size()-1)cout<<" ";
    else cout<<endl;
  }
}
int main(){
  cin>>n;
  for(int i=1;i<=n;i++)cin>>mid[i];
  for(int i=1;i<=n;i++)cin>>pre[i];
  root=build(1,n,1,n);
  bfs(root);
  return 0;
}

 

posted @ 2019-03-29 20:39  两点够吗  阅读(1476)  评论(0编辑  收藏  举报