利用后序和中序遍历恢复二叉树

利用后序和中序遍历恢复二叉树

  利用后序和中序遍历可以将二叉树还原出来,以便于进行其他树的操作。在这里我们还原出二叉树之后进行先序遍历来求得先序遍历的结果,我们约定还原树的函数叫做RestoreTree()。

过程

后序遍历实例:C B E H G I F D A

中序遍历实例:B C A E D G H F I

中序遍历开始位置,结束位置记做z1,z2,后序的记为h1,h2

  1. 新建一颗空树,左右孩子置空
  2. 拿到后序遍历的最后一个结点,其位置为z2,将该值存入树的数据域
  3. 在中序遍历的序列中以遍历的方式找到最后一个结点的位置,记为i
  4. 如果i!=z1,说明以该结点为根结点的树有左子树,以递归的方式,调用当前函数恢复左子树
  5. 如果i!=z2,说明以该结点为根结点的树有右子树,以递归的方式调用当前函数恢复右子树
  6. 返回树的根结点值
需要注意的地方

  在恢复左右子树的时候,其位置需要算出来,即h1,h2和z1,z2的值需要重新计算,并在更新之后传递给RestoreTree()函数。以构建左子树为例,左子树的首元素下标为z1,最后一个元素下标为i-1,对应的h1的值为h1,h2的值为h1+(i-z1-1),也就是h1当前的位置向前移动i-z1-1个长度。

代码实现

以实现之前提到的字母序列为例

#include<stdio.h>
#include<stdlib.h>

typedef struct Bitree{
	char data;
	struct Bitree* lchild;
	struct Bitree* rchild;
}*bitree,bitnode;
bitree Createtree(void);
bitree Restoretree(int h1,int h2,int z1,int z2);
void Preorder(bitree bt);
char in[50],post[50];
int main(void)
{
	int n;
	scanf("%d",&n);
	getchar();
	//getchar()用于清除回车
	for(int i = 0;i < n;i++)
		scanf("%c",&post[i]);
	getchar();
	for(int i = 0;i < n;i++)
		scanf("%c",&in[i]);
	bitree b = Restoretree(0,n-1,0,n-1);
	Preorder(b);
	printf("\n");
	return 0;
}

bitree Createtree(void)
{
	bitree bt = (bitree)malloc(sizeof(bitnode));
	bt->lchild = bt->rchild = NULL;
	return bt;
}
bitree Restoretree(int h1,int h2,int z1,int z2)
{
	bitree bt = Createtree();
	bt->data = post[h2];
	for(int i = z1;i <= z2;i++)
	{
		if(in[i]==post[h2])
		{
			if(i!=z1)//存在左子树,构建左子树
				bt->lchild = Restoretree(h1,h1+i-z1-1,z1,i-1);
			if(i!=z2)//存在右子树,构建右子树
				bt->rchild = Restoretree(h2-z2+i,h2-1,i+1,z2);
			break;//找到以后跳出遍历
		}
	}
	return bt;
}
void Preorder(bitree bt)
{
	if(!bt)
		return;
	printf("%c ",bt->data);
	Preorder(bt->lchild);
	Preorder(bt->rchild);
}

  由于代码在恢复树的时候先恢复的根结点,然后访问的左右子树,因此,恢复的过程也相当于一个先根遍历的过程.如果只想求先根遍历,可以不建树.我们可以删掉先根遍历的函数,同时简化一些其他的语句.修改后的代码如下:

#include<stdio.h>
typedef struct Bitree{
	char data;
	struct Bitree* lchild;
	struct Bitree* rchild;
}*bitree,bitnode;
void Restoretree(int h1,int h2,int z1,int z2);
char in[50],post[50];
int main(void)
{
	int n;
	scanf("%d",&n);
	getchar();
	for(int i = 0;i < n;i++)
		scanf("%c",&post[i]);
	getchar();
	for(int i = 0;i < n;i++)
		scanf("%c",&in[i]);
	Restoretree(0,n-1,0,n-1);
	printf("\n");
	return 0;
}

void Restoretree(int h1,int h2,int z1,int z2)
{
	printf("%c ",post[h2]);
	for(int i = z1;i <= z2;i++)
	{
		if(in[i]==post[h2])
		{
			if(i!=z1)//存在左子树,访问左子树
				Restoretree(h1,h1+i-z1-1,z1,i-1);
			if(i!=z2)//存在右子树,访问右子树
				Restoretree(h2-z2+i,h2-1,i+1,z2);
			break;//找到以后跳出遍历
		}
	}
}

两段代码得到的结果是一样的,以下是样例输入:

9
CBEHGIFDA
BCAEDGHFI

以下是输出:

A B C D E F G H I 
代码拓展

  在这里补充一段利用先序遍历和中序遍历来还原二叉树并进行后序遍历的代码。

#include<stdio.h>
#include<stdlib.h>

typedef struct BiTree{
    int data;
    struct BiTree* lchild;
    struct BiTree* rchild;
}bitnode,*bitree;
void Postorder(bitree bt);
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2);

int main()
{
    char pre[10] = {"DBACEGF"},in[10] = {"ABCDEFG"};
    bitree bt= RestoreTree(pre,in,0,6,0,6);
    Postorder(bt);
    return 0;
}
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2)
{
    bitree bt = (bitree)malloc(sizeof(bitnode));
    bt->lchild = bt->rchild = NULL;
    bt->data = pre[q1];
    for(int i = z1;i<=z2;i++)
    {
        if(in[i]==pre[q1])
        {
            if(i!=z1)
                bt->lchild = RestoreTree(pre,in,q1+1,q1+i-z1,z1,i-1);
            if(i!=z2)
                bt->rchild = RestoreTree(pre,in,q1+i-z1+1,q2,i+1,z2);
            break;
        }
    }
    return bt;
}
void Postorder(bitree bt)
{
    if(bt->lchild!=NULL)
        Postorder(bt->lchild);
    if(bt->rchild)
        Postorder(bt->rchild);
    printf("%c",bt->data);
}

  代码和之前一样可以简化,简化以后,不需要建树,也可以进行后序遍历。

#include<stdio.h>
#include<stdlib.h>

typedef struct BiTree{
    int data;
    struct BiTree* lchild;
    struct BiTree* rchild;
}bitnode,*bitree;
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2);

int main()
{
    char pre[10] = {"DBACEGF"},in[10] = {"ABCDEFG"};
    RestoreTree(pre,in,0,6,0,6);
    return 0;
}
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2)
{
    for(int i = z1;i<=z2;i++)
    {
        if(in[i]==pre[q1])
        {
            if(i!=z1)
                RestoreTree(pre,in,q1+1,q1+i-z1,z1,i-1);
            if(i!=z2)
                RestoreTree(pre,in,q1+i-z1+1,q2,i+1,z2);
            break;
        }
    }
    printf("%c",pre[q1]);
}

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值