背景:
树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。
假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,请构建这棵二叉树。
正文:
总体思路:与根据先序和中序建树相类似,都是由递归来实现。
- 根据层序遍历的特点,层序序列中第一个元素就是根节点
root
。 - 确定该节点在中序序列中的位置。则该位置左边的都是左子树,右边都是右子树。
- 左子树的根节点就是
root
的左孩子,右子树的根节点就是root
的右孩子。 - 递归到左子树和右子树。
- 一直递归,便确定了每个节点的左右孩子。
大体思路明白了,如何具体实现呢?
1、如何确定根节点?
该(分)中序序列的第一个在总的先序序列中出现的节点就是根节点。
2、如何确定根节点在中序序列中的位置?
在输入中序序列的时候,开一个map
数组,map[i]
就是记录了节点i
在中序序列中的位置。
3、递归到左右子树是什么意思?如何实现呢?
挑出左右子树的中序和层序序列,重复上述思路中的过程,最终返回根节点。( 其根节点是其父树的左(右)孩子。)
好了,接下来就交给码哥吧:
struct T{
int l,r;
}a[N];
int build(int il,int ir) //##核心函数:递归实现寻找每个节点的左右孩子
{
int root,k;
for(int i=1;i<=n;i++){ //中序数列il到ir位置的数中,第一个在层序数列中出现的就是根节点
if(mp[floor[i]]>=il&&mp[floor[i]]<=ir){
root=floor[i];
break;
}
}
k=mp[root];
//k>il,根节点左边有位置,说明有左子树
if(k>il) a[root].l=build(il,k-1); //中序数列中根节点root位置左边的是左子树
if(k<ir) a[root].r=build(k+1,ir);
return root; //返回的是根节点!(作为其父树的左孩子或者右孩子)
}
void print(int x) //先序输出
{
cout<<x<<" ";
if(a[x].l) print(a[x].l);
if(a[x].r) print(a[x].r);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>in[i]; //输入中序序列
mp[in[i]]=i; //记录位置
}
for(int i=1;i<=n;i++) cin>>floor[i]; //输入层序序列
build(1,n); //建树
print(floor[1]); //先序输出
return 0;
}