由二叉树的中序序列和后序序列(或前序)得到层次遍历序列

这篇博客探讨了两种不同的方法来重建并遍历二叉树。第一种方法是通过中序和后序序列构建二叉树,然后使用广度优先搜索进行层次遍历。第二种方法则在遍历过程中记录节点的深度,最后按深度排序输出节点。这两种方法都利用了后序序列的特性来辅助构建和遍历二叉树结构。
摘要由CSDN通过智能技术生成

题目

 思路一:

由于中序序列加前或后序列能唯一确定一个树,那就把这个树建出来,再用bfs一层一层遍历

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
struct Node {
	int val,l,r;
} node[MAX];
int tot;
int c[MAX],b[MAX]; 
int dfs(int len,int b[],int c[]) {//中序,后序 
	if(len <= 0) return -1;
	if(len == 1) {
		node[++tot].val = b[1];
		node[tot].l=node[tot].r = -1;
		return tot;
	}
	node[++tot].val = c[len];
	int res = tot;
	int l;
	for(l = 1; l<=len; l++) {
		if(b[l] == c[len]) break;
	}
	node[res].l = dfs(l-1,b,c);
	//node[res].r = dfs(len-l,b+l-1,c+l);
	node[res].r = dfs(len-l,b+l,c+l-1);
	
	return res;
} 
void bfs() {
	queue<int> q;
	q.push(1);
	while(q.size()) {
		int cur = q.front();q.pop();
		if(cur != 1) printf(" ");
		printf("%d",node[cur].val);
		if(node[cur].l != -1) q.push(node[cur].l);
		if(node[cur].r != -1) q.push(node[cur].r);
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i = 1; i<=n; i++) scanf("%d",c+i);
	for(int i = 1; i<=n; i++) scanf("%d",b+i);
	dfs(n,b,c);
	//printf("%d",node[1].val);
	bfs();
	return 0 ;
}

思路二:

不把树建出来,在遍历树的时候给树的深度也表示出来,最后把节点按深度排序,然后输出

我们根据后序序列的性质发现一个规律,就是后序序列从左到右,当一个节点的相邻左边的节点可能是这个节点的右孩子(当且仅当它的右孩子存在时),可能是这个节点的左孩子(当且仅当右孩子不存在,左孩子存在时)。

而我们可以根据后序序列的最后一个值来找到中序序列中的中间节点,跟距中序序列提供的区间范围来判断这个节点的孩子是否存在

这个性质也可以帮助大家根据两个序列来快速画出二叉树的图,大家不妨一试。

以下代码就是利用分治的方法,分治中序序列中的左右子树,其间根据dfs的层数来判断深度

最后由于我们是先右再左的方式遍历,而一般的层次遍历是从左往右,需要先用冒泡排序按深度排序(稳定)

得到从右往左的序列,之后每层倒着输出。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
const int N = 33;
int back[N],mid[N];
int n,t;
vector<pair<int,int> >deep;
//递归出口是区间长度为0
void erfen(int i,int j,int cnt)
{
    if(i>j||i<1||j>n) return;
     int x=back[t--],middle=-1;    
      deep.push_back({cnt+1,x});//  
      int k;
     for( k=i;k<=j;k++)  
    if(mid[k]==x)
      {middle=k;
      break;}
      if (middle==-1) return;
      erfen(middle+1,j,cnt+1);
      erfen(i,middle-1,cnt+1);
}
int main()
{

    cin>>n;
    for(int i=1;i<=n;i++) cin>>back[i];//找出节点深度,排序后输出
    for(int i=1;i<=n;i++) cin>>mid[i];
    t=n;
    erfen(1,n,0);
    int leng=deep.size();
   for(int i=0;i<leng-1;i++)
   {
       for(int j=0;j<leng-1-i;j++)
        {
            int x=deep[j].first,y=deep[j+1].first;
            if(x>y)
            {
                int t=x;
                deep[j].first=deep[j+1].first;
                deep[j+1].first=t;
                 t=deep[j].second;
                deep[j].second=deep[j+1].second;
                deep[j+1].second=t;
            }
        }
   }
    int flag=0;
   for (int i = 0; i <n; i ++ ) 
    {
        int j=i;
        while(deep[j+1].first==deep[j].first) j++;
        for (int k = j; k>= i; k -- ) 
       if(!flag)
        {
            cout<<deep[k].second;
            flag=1;
        }
        else cout<<' '<<deep[k].second;
        i=j;
       
    }
}
/*7 
4 5 3 7 6 2 1
5 3 4 1 7 2 6*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值