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的空间,必定栈溢出,所以使用类似于静态数组的方式,只是对结点加了一个表示位置的的成员,最后再对数组根据位置信息排序,即得到层次序列啦
更新:层序遍历可以只用链式结构,类似于广搜(我一时没想起来),所以很多做法都行,可以不用数组存储结点,是我太笨了QWQ
另一种比较好的(递归)解法:https://www.freesion.com/article/2513947642/

示意图:
在这里插入图片描述

ps:其实我觉得还是非递归比较好写

#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;
    }

然而实际上这题目只用下标索引左右节点就可以,因为数据并没有打算为难你。。。

#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;
}
posted @ 2022-11-17 23:03  林动  阅读(14)  评论(0编辑  收藏  举报