已知二叉树前序中序遍历,建立二叉树并输出后序遍历序列(zoj1944、hdu1710)


一、相关题目链接

zoj:1944 Tree Recovery
hdu:1710 Binary Tree Traversals


二、题意简述

输入一个二叉树的前序遍历和中序遍历序列,要求输出该二叉树的后序遍历序列。


三、解析

学过二叉树的同学应该知道,前序遍历顺序是根、左、右,中序遍历顺序是左、根、右,由此容易推导出,前序序列的第一个结点必定是整棵树的根。接下来从中序序列中寻找它的位置,由中序的特性,以该结点为分界线,其左侧的结点位于树的左子树上,而右侧的结点位于树的右子树上。
在这里插入图片描述

二叉树可以分解成若干个子树,这些子树都保留二叉树的特性,由此我们不难推出,上面的方法是可以递归的,即从前序序列中不断找到子树的根,再在中序序列以该子树根为界线中划分出子树的左右子树。
在这里插入图片描述

我们需要用两个数组接收前序中序遍历的字符串。先设置一个在前序中的指针root_i,它的作用是指明我们当前需要建立的根结点的值。通过left和right这两个参数来划分子树的范围,再对这个范围内的字符串进行遍历,直到在中序中找到结点值和root_i指向的值相同时候的下标i,此时,我们便可以建立新结点,同时使root_i后移。找这样一个i的原因是方便划分左右子树在中序字符串中的范围,左子树是(left,i-1),右子树是(i+1,right)。
递归到叶子结点时,left==right,再往下递归,会使下一层的left>right,所以以此作为递归结束的条件。同时,指针引用的特性保证开辟的结点不会跑丢。


四、代码

注:以ZOJ的题目要求为例

#include<iostream>
#include<cstring>
using namespace std;
const int MAX_N = 30;
char preor[MAX_N];//存储前序序列
char inor[MAX_N];//存储中序序列
int root_i=0;//在前序序列中指向根的指针
struct node//二叉树结点
{
	char v;
	node *l, *r;
	node(char c = '0', node *le = NULL, node *ri = NULL) :v(c), l(le), r(ri) {}
};
void createTree(int left,int right,node *&root)
{
    if(left>right)
        return;
    for(int i=left;i<=right;i++)
    {
        if(preor[root_i]==inor[i])//找到根
        {
             if(root==NULL)
             {
                root=new node(inor[i]);
                root_i++;
                createTree(left,i-1,root->l);
                createTree(i+1,right,root->r);
             }
             
        }
    }
}
void postOrder(node *&root)//后序遍历
{
    if(root==NULL)
        return;
    postOrder(root->l);
    postOrder(root->r);
    printf("%c",root->v);
}
int main()
{
	while(~scanf("%s",&preor))
    {
        scanf("%s",&inor);
        node *tr=NULL;
        createTree(0,strlen(inor)-1,tr);
        postOrder(tr);
        printf("\n");
        root_i=0;
    }
	return 0;
}

因为是用于通过竞赛题目,所以我们可以不用考虑空间回收的问题。在实际应用中,程序结束前需要依次回收开辟的空间:

void remove(node *root)
{
	if(root==NULL)
		return;
	remove(root->l);
	remove(root->r);
	delete root;
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值