还原二叉树

一、根据先序遍历和中序遍历恢复二叉树

思路:

根据先序遍历的第一个元素建立根结点;然后在中序列表中找到该元素,以确定根结点的左右子树的中序列;再在先序序列中确定左右子树的先序序列;最后由左子树的先序序列中确定左右子树的先序序列;最后由左子树的先序序列与中序序列建立左子树,由右子树的先序序列与中序序列建立左子树,由右子树的先序序列和中序序列建立右子树。

 

rebitree(char pread[],char incd[],bitree root)
{
    if(n<=0) root=NULL;
    else preinod(preod,1,n,inod,1,n,&root);
}
void preinod(char preod[],int i,int j,char inod[],int k,int h,botree *t)
{
    *t=(bitnode *)malloc(sizeof(bitnode));
    *t->data=preod[i]; // 先序序列的第一个值为二叉树的根
    m=k;
    while(inod[m]!=preod[i]) //在中序序列中寻找根结点
        m++;
    if(m==k) *t->lchild=NULL;
    else preinod(pred,i+1,i+m-k,inod,k,m-1,&(*t-<lchild));    //生成左子树
    if(m==h)
        else preinod(preod,i+m-k+1,j,inod,m+1,h,&(*t->rchild));   //生成右子树
}

二、由中序和后序确定二叉树

      //inorder[]:中序序列
      //preorder[]:后序序列
      TreeNode* traversal (int inorder[], int inorderBegin, int inorderEnd, int preorder[], int preorderBegin, int preorderEnd)
       {
        if (preorderBegin == preorderEnd) return NULL;

        int rootValue = preorder[preorderBegin]; // 注意用preorderBegin 不要用0
        TreeNode* root ;
        root->data=rootvalue;

        if (preorderEnd - preorderBegin == 1) return root;

        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 中序左区间,左闭右开[leftInorderBegin, leftInorderEnd)
        
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        
        // 中序右区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;

        // 切割前序数组
        // 前序左区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
        int leftPreorderBegin =  preorderBegin + 1;
        int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 终止位置是起始位置加上中序左区间的大小size
        
        // 前序右区间, 左闭右开[rightPreorderBegin, rightPreorderEnd)
        int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
        int rightPreorderEnd = preorderEnd;

        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  preorder, leftPreorderBegin, leftPreorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);

        return root;
    }

     TreeNode * buildTree(int preorder[], int inorder[]) 
     {
        if (strlen(inorder)== 0 || strlen(preorder)== 0)
         return NULL;
        // 参数坚持左闭右开的原则
        return traversal(inorder, 0, strlen(inorder), preorder, 0, strlen(preorder));
    }

[USACO3.4] 美国血统 American Heritage

题目描述

农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形的方法。

你的任务是在被给予奶牛家谱的“树中序遍历”和“树前序遍历”的符号后,创建奶牛家谱的“树的 后序遍历”的符号。每一头奶牛的姓名被译为一个唯一的字母。(你可能已经知道你可以在知道树的两 种遍历以后可以经常地重建这棵树。)显然,这里的树不会有多于 26 个的顶点。 这是在样例输入和 样例输出中的树的图形表达方式:

   C

 /     \

/  \

B   G

/  \  /

A  D  H

    /  \

   E  F

树的中序遍历是按照左子树,根,右子树的顺序访问节点。

树的前序遍历是按照根,左子树,右子树的顺序访问节点。

树的后序遍历是按照左子树,右子树,根的顺序访问节点。

输入格式

第一行: 树的中序遍历

第二行: 同样的树的前序遍历

输出格式

单独的一行表示该树的后序遍历。

样例输入

ABEDFCHG

CBADEFGH

样例输出

AEFDBHGC

提示

题目翻译来自NOCOW。

USACO Training Section 3.4

思路:
根据二叉树的先序遍历(根结点,左子树,右子树)我可以知道 A 是根结点,再在中序序列中找到根结点,进行分割,中序遍历(左子树,根结点,右子树),找到根节点后,可以按照这个遍历顺序,找到左子树的部分和右子树的部分。再依据左子树的个数和右子树的结点个数,划分先序序列的左子树和右子树,输出的时候以后序遍历的顺序输出(左子树,右子树,根结点)。

#include<stdio.h>
#include<string.h>
typedef struct tree
{
    char data;
    struct tree *left;
    struct tree *right;
}node;
char in[100],or[100];
void traversal(int inb,int ine,int orb,int ore)
{
    int i;
  for(i=inb;i<=ine;i++)
  {
    if(in[i]==or[orb])   //查找中序序列根结点,然后进行分割
    { traversal(inb,i,orb+1,orb+i-inb);  //先序序列进行左子树复原的时候记得去除根结点,根结点在第一个位置
     traversal(i+1,ine,orb+1+i-inb,ore);   //恢复右子树
     printf("%c",in[i]);
    }
  }
}
int main()
{
    scanf("%s",in);
    scanf("%s",or);
    traversal(0,strlen(in)-1,0,strlen(or)-1);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值