二叉树中序层序序列还原树

本文介绍了如何通过中序和层序序列还原二叉树,重点讲解了递归和非递归两种方法。递归方法利用中序序列中根节点的下标最小的特点;非递归方法则借助队列,结合层序和中序序列确定子树。文中提供了具体的代码实现和运行结果。

先序中序,后序中序,中序层序都可以唯一确定一棵树;

先序后序无法还原树的原因:当只有一棵子树时无法确定是左子树还是右子树;

写了一下中序层序还原树的递归和非递归方法。

用于检验算法的二叉树

中序序列为:6 7 4 11 2 5 9 8 10 1 3

层序序列为:2 7 5 6 11 1 4 8 3 9 10

递归方法

对于元素唯一的序列,记录层序各结点对应的下标,中序遍历序列的根节点肯定是在层序序列中下标数最小的结点!

  • 代码
#include<bits/stdc++.h>
using namespace std;
#define N 1000 
typedef struct node
{
	int v;
	node *l,*r;
}*pnode;
int car[N],inar[N];
map<int,int> cvis;
pnode func(int l,int r)
{
	pnode p=NULL;
	if(l<r)
	{
		p=(pnode)malloc(sizeof(node));
		int mid=l;
		for(int i=l+1;i<r;i++)
			if(cvis[inar[mid]]>cvis[inar[i]])
				mid=i;
		p->v=inar[mid];
		p->l=func(l,mid);
		p->r=func(mid+1,r);
	}
	return p;
}
void preorder(pnode p)  //先序遍历
{
	if(p)
	{
		printf("%d ",p->v);
		preorder(p->l);
		preorder(p->r);
	}
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
			scanf("%d",&inar[i]);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&car[i]);
			cvis[car[i]]=i;
		}	
		pnode BTree;
		BTree=func(0,n);
		preorder(BTree);
		printf("\n");
	}
	return 0;
}
  • 运行结果

非递归方法

因为层序是使用队列来进行遍历的,所以还原时也可以用队列进行,层序序列确定根结点,中序序列确定左右子树,随后在队列中记录每个子树对应的根结点,根节点的前序为-1,如果存在结点才需要对层序对应值i++

可以用孩子表示法,或者双亲表示法来保存结果,只要对孩子表示的结果递归处理就可以得到二叉链表的存储结果。

  • 代码
#include<bits/stdc++.h>
using namespace std;
#define N 100
typedef int DataType;
struct cnode  //双亲建树 
{
	int p;
	int l,r;
	cnode(){
	} 
	cnode(int p,int l,int r):p(p),l(l),r(r){
	}
};
int parents[N]; 
vector<int> child[N]; 
DataType ar1[N],ar2[N];
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)  //中序 
			scanf("%d",&ar1[i]);
		for(int i=0;i<n;i++)  //层序 
			scanf("%d",&ar2[i]);
		memset(parents,-1,sizeof(parents));
		queue<cnode> que;
		que.push(cnode(-1,0,n));
		int i=0; 
		while(!que.empty())
		{
			cnode m=que.front();
			que.pop();
			if(m.l<m.r)
			{	
				int v=ar2[i];
				int k=m.l;
				while(ar1[k]!=v&&k<m.r)
					k++;
				parents[k]=m.p; 
				if(m.p!=-1)
					child[m.p].push_back(k);
				que.push(cnode(k,m.l,k));
				que.push(cnode(k,k+1,m.r));
				i++; //!!! 
			}
		}
		printf("\n孩子表示法\n"); 
		for(int i=0;i<n;i++)
		{
			if(child[i].size()==0)
				printf("%d is leaf\n",ar1[i]);
			else
			{
				printf("%d kids:",ar1[i]);
				for(int j=0;j<child[i].size();j++)
					printf(" %d",ar1[child[i][j]]);
				puts("");
			}
		}
		printf("\n双亲表示法\n");
		for(int i=0;i<n;i++)
			printf("%d p:%d\n",ar1[i],parents[i]==-1?-1:ar1[parents[i]]);
	}
	return 0;
} 
  • 运行结果

编写程实现二叉树的如下操作: 1) 建立二叉链表 2) 二叉树的先、中、后遍历 3) 求二叉树的叶子结点个数 4) 将二叉树中所有结点的左、右子相互交换 输入:   按完全二叉树的层次关系给出二叉树的遍历列(#表示虚结点,数据结点为单一字符)。 输出:   二叉树的凹入表示   二叉树的先列、中列、后列   二叉树叶子结点个数   左、右子相互交换后的二叉树的凹入表示   左、右子相互交换后的二叉树的先列、中列、后列。 说明:   在输出凹入表示的二叉树时,先输出根结点,然后依次输出左右子,上下层结点之间相隔 3 个空格。 测试输入 期待的输出 时间限制 内存限制 额外进程 测试用例 1 以文本方式显示 abc#de↵ 以文本方式显示 BiTree↵ a↵ b↵ d↵ c↵ e↵ pre_sequence : abdce↵ in_sequence : bdaec↵ post_sequence : dbeca↵ Number of leaf: 2↵ BiTree swapped↵ a↵ c↵ e↵ b↵ d↵ pre_sequence : acebd↵ in_sequence : ceadb↵ post_sequence : ecdba↵ 1秒 64M 0 测试用例 2 以文本方式显示 abcdefg↵ 以文本方式显示 BiTree↵ a↵ b↵ d↵ e↵ c↵ f↵ g↵ pre_sequence : abdecfg↵ in_sequence : dbeafcg↵ post_sequence : debfgca↵ Number of leaf: 4↵ BiTree swapped↵ a↵ c↵ g↵ f↵ b↵ e↵ d↵ pre_sequence : acgfbed↵ in_sequence : gcfaebd↵ post_sequence : gfcedba↵ 1秒 64M 0
10-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值