P1132已知先后序和中序求先序排列解题报告

Name: 已知先后序和中序,求出它的先序排列

  Copyright: 始发于goal00001111的专栏;允许自由转载,但必须注明作者和出处

  Author: goal00001111

  Date: 11-12-08 10:58

  Description:

题目描述:

描述 Description        

给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度≤8)

输入格式 Input Format      

      第一行为二叉树的中序序列

    第二行为二叉树的后序序列

输出格式 Output Format    

      一行,为二叉树的先序序列

样例输入 Sample Input      

      BADC BDCA

样例输出 Sample Output    

      ABCD

     

题目分析:

已知中序和前序排列,或者已知中序和后序序列,都能够构造一棵二叉树,此题考查后者。

前序遍历的规律是:输出根结点,输出左子树,输出右子树; 

中序遍历的规律是:输出左子树,输出根结点,输出右子树;

后序遍历的规律是:输出左子树,输出右子树,输出根结点;

根据中序和后序序列的规律,我们可以知道构造二叉树的过程是一个递归的过程,根据给定的 中序和后序序列,建立二叉树的根结点,并将中序序列划分为左子树序列和右子树序列,然后分别把左子树序列和右子树序列递归的构造左子树和右子树。

具体的算法是分别用数组mid[lm..rm]post[tp..rp]存储给定的中序和后序序列。易知post[rp]为根结点,创建二叉树的根结点t,设t->data = post[rp];遍历mid,寻找根结点post[rp]的下标pos,则mid[lm..pos-1]为左子树序列,mid[pos+1..rm]为右子树序列;左子树序列的长度lenL= pos - lm,右子树序列的长度lenR= rm - pos

很明显,若pos == lm,则lenL = 0,说明根结点无左子树;若pos == rm,则lenR = 0,说明根结点无右子树; 

根据后序序列的规律,可以知道根结点t的左子树的后序排列为post[lp..lp+lenL-1];

根结点t的右子树的后序排列为post[lp+lenL..rp-1]

采用同样的方法递归构造根结点t的左右子树。

以样例输入为例:

中序序列:BADC

后序序列:BDCA  

1.得到根结点t->data = 'A';

2.遍历中序序列mid,得到mid[pos] = 'A'lenL = 1

3.得到根结点t的左子树的中序序列为mid[lm..pos-1] = "B",右子树的中序序列为mid[pos+1..rm] = "DC";根结点t的左子树的后序序列为post[lp..lp+lenL-1] = "B",右子树的后序序列为post[lp+lenL..rp-1] = "DC";

4.递归构造根结点t的左子树t->lc,设t= t->lc

           1.得到根结点t->data = 'B';

           2.遍历中序序列mid,得到mid[pos] = 'B'lenL = 0

           3.得到根结点t的左右子树均为空,返回调用函数。

5. 递归构造根结点t的右子树t->rc,设t= t->rc

           1.得到根结点t->data = 'C';

           2.遍历中序序列mid,得到mid[pos] = 'C'lenL = 1

           3.得到根结点t的左子树的中序序列为"D",后序序列为"D";右子树为空,

           4.递归构造根结点t的左子树t->lc

6.最后得到整棵二叉树,前序遍历二叉树,得到前序序列:ABCD

 

说明:

算法思想:递归和分治。

数据结构:数组,二叉树。

时间复杂度:O(N);

空间复杂度:O(N);

程序语言:分别用c++pascal实现。

 

附注:

若题目改为已知中序和前序序列,输出后序序列,因为先序序列pre[lp..rp]中根结点是第一个元素,所以只需将函数中的根结点数据由t->data = post[rp] 改为t->data = pre[lp] 然后在递归构造左右子树时注意左子树中序序列为mid[lm+1..pos-1],右子树中序序列为mid[pos+1..rm],左子树先序序列为pre[lp+1..lp+lenL],右子树先序序列为pre[lp+lenL+1..rp]

最后后序遍历二叉树就行了。 

 

c++代码:

 

#include<iostream>

#include<string>

 

using namespace std;

 

typedef struct BTNode{

      char data;

      struct BTNode *lc, *rc;//左,右孩子指针

} *BTree;

 

void PostBtree(BTree & t, string mid, string post, int lm, int rm, int lp, int rp);

void Preorder(BTree p);

 

int main(int argc, char* argv[])

{

    string mid, post;

    BTree root;

   

    cin >> mid;

    cin >> post;

    PostBtree(root, mid, post, 0, mid.size()-1, 0, post.size()-1);

    Preorder(root);

   

    system("pause");

    return 0;

}

 

/*

函数名称:PostBtree

函数功能:给出一棵二叉树的中序与后序序列,构造这棵二叉树。

输入参数: BTree & t:二叉树的结点t

          string mid:存储了二叉树的中序序列的字符串

          string post:存储了二叉树的后序序列的字符串

          int lm, int rm:二叉树的中序序列在数组mid中的左右边界

          int lp, int rp:二叉树的后序序列在数组post中的左右边界

*/

void PostBtree(BTree & t, string mid, string post, int lm, int rm, int lp, int rp)

{

    t = new BTNode; //构造二叉树根结点

    t->data = post[rp];

    t->lc = t->rc = NULL;

   

    int pos = lm;

    while (mid[pos] != post[rp])

        pos++;

    int lenL = pos - lm;

    if (pos > lm)//有左孩子,递归构造左子树

        PostBtree(t->lc, mid, post, lm, pos-1, lp, lp+lenL-1);

    if (pos < rm)//有右孩子,递归构造右子树

        PostBtree(t->rc, mid, post, pos+1, rm, lp+lenL, rp-1);

}

//先序遍历

void Preorder(BTree p)

{

       if(p != NULL)

       {

              cout << p->data; //输出该结点

              Preorder(p->lc); //遍历左子树

              Preorder(p->rc); //遍历右子树

       }

}

 

 

PASCAL代码:

 

PROGRAM EXAMP1132(INPUT, OUTPUT);

TYPE

    BTree = ^node;

    node = record

               data : char;

               lc, rc : BTree;

           end; {record}

VAR

    mid, post : string;

    root : BTree;

 

{先序遍历}

PROCEDURE Preorder(t : BTree);

    begin

           if t <> nil then

           begin

               write(t^.data);  {输出该结点}

               Preorder(t^.lc); {遍历左子树}

               Preorder(t^.rc); {遍历右子树}

        end;

    end;

 

{已知后序和中序,构造二叉树}

PROCEDURE PostBtree(var t : BTree; mid, post : string; lm, rm, lp, rp : integer);

    var

        pos, lenL : integer;

    begin

        new(t);

        t^.data := post[rp];

        t^.lc := nil;   

        t^.rc := nil; 

       

        pos := lm;

        while mid[pos] <> post[rp] do

            inc(pos);

       

        lenL := pos - lm;

        if pos > lm then {有左孩子,递归构造左子树}

            PostBtree(t^.lc, mid, post, lm, pos-1, lp, lp+lenL-1);

        if pos < rm then {有右孩子,递归构造右子树}

            PostBtree(t^.rc, mid, post, pos+1, rm, lp+lenL, rp-1);

    end; {PostBtree}

          

BEGIN

    readln(mid);

    readln(post);

    PostBtree(root, mid, post, 1, ord(mid[0]), 1, ord(post[0]));

    Preorder(root);

END.  

     


     
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值