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

思路
由序列重建二叉树只有三种情况:
前+中
后+中
层+中(类似于前+中)

即:必须要中序序列,其他序列两两组合都不能唯一确定一个二叉树

重建思路
后序用来从后向前取得某个子树的根节点,而中序用来提供当前结点对于已建结点的左右孩子关系

层序遍历需要存储位置信息,不能纯用链式结构,需要数组来存每个结点,由于N=30,所以用数组下标作结点的位置的话极端情况(全在右子树)需要2^30的空间,必定栈溢出,所以使用类似于静态数组的方式,只是对结点加了一个表示位置的的成员,最后再对数组根据位置信息排序,即得到层次序列啦

22.12.2更新:我那时候是真滴菜,连做完题写的思路(上面的删除线部分)都是错的,可见学好数据结构有多重要qwq,基础不牢地动山摇

层序遍历可以直接用队列广度优先遍历,也可以所以很多做法都行,可以不用数组存储结点(顺序存储),是我太笨了QWQ

二叉树的题目最通用的解法还是:静态链表

本题目的最通用的解法应该是:静态链表存储重建的二叉树+bfs遍历

别人的指针链表解法:https://www.freesion.com/article/2513947642/

用指针链表重建二叉树,再对二叉树bfs得到层序(bfs的时候,队列只需要存储结点指针即可,不必存储结点,省空间)

静态链表+顺序存储的位置信息

静态链表又可以分为两种
一种是多个数组共用一套地址,每个数组表示一个字段
另一种是一个结构体数组,结构体包含结点所有字段

#include <bits/stdc++.h>

using namespace std;

struct node 
{
	int l,r,w,wei;
} a[50];

int hou[50];
map<int,int> zon;
int n,cnt,h=-1;

bool cmp(node a,node b)
{
	return a.wei<b.wei;
}

int main()
{
	cin>>n;
	for(int i=0;i<n;++i)cin>>hou[i];
	for(int i=0;i<n;++i)
	{
		int x;cin>>x;
		zon[x]=i;
	}
	
	for(int i=n-1;i>=0;--i)
	{
		int x=hou[i];
		if(h==-1)
		{
			h=cnt;
			a[cnt].wei=1;
			a[cnt++].w=x;
		}
		else
		{
			int p=h;
			while(1)
			{
				if(zon[x]<zon[a[p].w])
				{
					if(a[p].l!=0)
						p=a[p].l;
					else 
					{
						a[p].l=cnt;
						a[cnt].wei=a[p].wei*2;
						a[cnt++].w=x;
						break;
					}
				}
				else
				{
					if(a[p].r!=0)
						p=a[p].r;
					else 
					{
						a[p].r=cnt;
						a[cnt].wei=a[p].wei*2+1;
						a[cnt++].w=x;
						break;
					}
				}
			}
		}
	}
	sort(a,a+cnt,cmp);
	for(int i=0;i<cnt;++i)
		if(i!=cnt-1)cout<<a[i].w<<" ";
		else cout<<a[i].w;

	return 0;
}
数组模拟链式结构,然后广搜得到层次序
    #include <bits/stdc++.h>
    using namespace std;
    const int N=50;
    int hou[N];
    map<int,int> zon;
    int n;
    int w[N],l[N],r[N],cnt=1;

    void bfs(){
        queue<int> q;
        q.push(1);
        cout<<w[1];
        while(!q.empty()){
            int t=q.front();q.pop();
            if(t!=1)
            cout<<" "<<w[t];
            if(l[t])q.push(l[t]);
            if(r[t])q.push(r[t]);
        }
    }
    int main()
    {
        cin>>n;
        for(int i=0;i<n;++i)cin>>hou[i];
        for(int i=0;i<n;++i){
            int x;cin>>x;
            zon[x]=i;
        }

        for(int i=n-1;i>=0;--i)
        {
            int x=hou[i];
            int dx=zon[x];
            if(cnt==1){
                w[cnt]=x;
                cnt++;
            }else {
                int t=1;
                while(1){
                    int dy=zon[w[t]];
                    if(dx<dy){
                        if(l[t]==0){
                            l[t]=cnt;
                            w[cnt]=x;
                            cnt++;
                            break;
                        }
                        else t=l[t];
                    }else {
                        if(r[t]==0){
                            r[t]=cnt;
                            w[cnt]=x;
                            cnt++;
                            break;
                        }
                        else t=r[t];
                    }

                }
            }

        }
        bfs();
        return 0;
    }
直接顺序存储

顺序存储非常浪费空间 n 个 节 点 最 坏 情 况 下 需 要 开 2 n 的 空 间 n个节点最坏情况下需要开2^n的空间 n2n
顺序存储仅适合存储完全二叉树。

只不过这题刚好可以过,因为数据原因。。。

#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int hou[50];
map<int,int> zon;
int n;
int w[N];

int main()
{
	cin>>n;
	for(int i=0;i<n;++i)cin>>hou[i];
	for(int i=0;i<n;++i){
		int x;cin>>x;
		zon[x]=i;
	}
	memset(w,-1,sizeof w);
	for(int i=n-1;i>=0;--i)
	{
		int x=hou[i];
		int dx=zon[x];
		if(w[0]==-1){
			w[0]=x;
		}else {
			int t=0;
			while(1){
				int dy=zon[w[t]];
				int l=t*2+1;
				int r=t*2+2;
				if(dx<dy){
					if(w[l]==-1){
						w[l]=x;
						break;
					}else t=l;
				}else {
					if(w[r]==-1){
						w[r]=x;
						break;
					}else t=r;
				}
			}
		}
	}
	for(int i=0;i<N;++i)
	{
		if(w[i]>-1){
			n--;
			if(n!=0)cout<<w[i]<<" ";
			else cout<<w[i];
		}
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wow_awsl_qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值