前几天写了1020 Tree Traversals (25 分)-PAT甲级这个题目,明白了如何由二叉树的后序遍历和中序遍历得到先序遍历和层次遍历。受这道题启发,思考了一下如何由二叉树的先序遍历和中序遍历得到后序遍历和层次遍历。思路和由二叉树的后序遍历和中序遍历得到先序遍历和层次遍历一样,只是递归函数的参数和位置有些改动。
1.得到后序遍历:我们知道二叉树的先序遍历中第一个为根节点,中序遍历中根节点位置的左右分别为左右子树,根据这个关系,我们可以还原出这个二叉树的结构。又由后序遍历中根节点最后输出,所以在后序遍历中我们只需要调整递归顺序即可(也就是“左右根”的访问顺序)。
递归函数的原型为post(int root,int start,int end),其中root为先序遍历中根节点的位置,start为中序遍历结果的左边界,end为中序遍历结果的右边界。定义一个变量i指向中序遍历中根节点的位置,根据根节点将树划分为左右子树,那么左子树的根节点为root+1,左子树左边界仍然为start,右边界变为i-1,右子树的根节点为i+1+root-start,右子树左边界变为i+1,右边界仍然为end,左子树递归为post(root+1,start,i-1),右子树递归为post(i+1+root-start,i+1,end)
,递归出口为start>end。
2.得到层次遍历:在得到后序遍历的基础上改进,以层次遍历的顺序给二叉树从0开始依次编号,当前编号设置为index,可知左子树的根节点的编号为index*2+1,右子树的根节点的编号为index*2+2(画图便知),将当前根节点的值填入当前编号中(使用一种容器保存结果,我这里使用的是map,内部自动实现从小到大的排序,),然后排序,最后再对结果顺序输出即可,得到的即为层次遍历的结果,递归函数的原型变为post(int root,int start,int end,index),左子树递归变为post(root+1,start,i-1,index*2+1),右子树递归变为post(i+1+root-start,i+1,end,index*2+2)
最后附上我的代码
由先序遍历和中序遍历得到后序遍历
#include <iostream>
#include <map>
#include <vector>
using namespace std;
vector <int> pre,in;
void post(int root,int start,int end)
{
if(start>end)
return;
int i=start;
while(i<end&&pre[root]!=in[i])
i++;
post(root+1,start,i-1);
post(i+1+root-start,i+1,end);
cout<<pre[root]<<" ";
}
int main()
{
int n,temp;
cin>>n;
for(int i=0;i<n*2;i++)
{
cin>>temp;
if(i<n)
pre.push_back(temp);
else
in.push_back(temp);
}
post(0,0,n-1);
return 0;
}
由先序遍历和中序遍历得到层次遍历
#include <iostream>
#include <map>
#include <vector>
using namespace std;
vector <int> pre,in;
map<int,int> level;
void post(int root,int start,int end,int index)
{
if(start>end)
return;
int i=start;
while(i<end&&pre[root]!=in[i])
i++;
post(root+1,start,i-1,index*2+1);
post(i+1+root-start,i+1,end,index*2+2);
level[index]=pre[root];
}
int main()
{
int n,temp;
cin>>n;
for(int i=0;i<n*2;i++)
{
cin>>temp;
if(i<n)
pre.push_back(temp);
else
in.push_back(temp);
}
post(0,0,n-1,0);
map<int,int>::iterator it;
for(it=level.begin();it!=level.end();it++)
{
if(it!=level.begin())
cout<<" ";
cout<<it->second;
}
return 0;
}