9 二叉树的重建 作者: 冯向阳 时间限制: 1S章节: 课程设计 DHU数据结构课程设计

ps:不是冯老师的学生,看不懂什么是外壳捏

解决问题的主要思路是,利用递归,每次递归确定一个根节点。

以先序+中序为例子:先序中第一个节点为根节点(A)

确定后在中序序列中找到此节点

for (int i = 0; i < inorder_len; i++)//在中序遍历中寻找根节点的位置
{
if (postorder[post_len-1] == inorder[i])
{
root_position = i;
break;
}
}

节点左侧为左子树,右侧为右子树,分别压入子树的vector准备递归(利用中序序列确定子树节点个数即可)

for (int i = 0; i < root_position; i++)//创建左子树的先序和中序序列,准备递归
{
left_in.push_back(inorder[i]); //中序遍历,根结点之前全是左子树
left_pre.push_back(preorder[i + 1]); //先序遍历,第一个是根节点,往后读取相同数量放入左子树
}
for (int i = root_position + 1; i < inorder_len; i++)//创建右子树的先序和中序序列,准备递归
{
right_in.push_back(inorder[i]);
right_pre.push_back(preorder[i]);
}

后序序列则是最后一个节点为根结点,其他一致。

问题描述 :

目的:现有两个结点序列,分别是对同一个二叉树进行前序遍历和中序遍历(或中序和后序)的结果。要求设计一个算法,重构该二叉树,并输出该二叉树按照后序(前序)遍历时的结点序列。假定二叉树所有的结点的数据域的值都不相同。二叉树的存储结构的建立参见二叉树应用1。

一、已知前序和中序的结果,进行二叉树的重构:

提示:preOrder按照先根再左再右的顺序递归遍历,inOrder按照先左再根再右的顺序递归遍历。

举例说明:preOrder的输入pre={A,B,D,G,H,C,E,I,F},inOrder的输入in={G,D,H,B,A,E,I,C,F}。首先按preOrder遍历的顺序依次访问各结点。访问过程中,通过in得知各子树内inOrder遍历的顺序,从而重建以当前访问结点c为根的左子树与右子树。即:设preOrder遍历的当前结点为c,c在in中的位置为m,m左侧就是c的左子树,右侧就是c的右子树。同理递归。

(2)

参考函数原型:

(1)//重建二叉树的存储结构 (外壳)
template<class ElemType>
BinaryTreeNode<ElemType> *ReBuildTree_Pre_In(vector[ElemType] &pre, vector[ElemType] &in);

(2)//重建二叉树的存储结构 (递归)
template<class ElemType>
BinaryTreeNode<ElemType> *reConstructCore_Pre_In(vector[ElemType] &pre, vector[ElemType] &in, int preStart, int preEnd, int inStart, int inEnd );

二、已知中序和后序的结果,进行二叉树的重构:

可参考一的思路。

参考函数原型:

(1)//重建二叉树的存储结构 (外壳)
template<class ElemType>
BinaryTreeNode<ElemType> *ReBuildTree_In_Post(vector[ElemType] &in, vector[ElemType] &post);

(2)//重建二叉树的存储结构 (递归)
template<class ElemType>
BinaryTreeNode<ElemType> *reConstructCore_In_Post(vector[ElemType] &in, vector[ElemType] &post, int inStart, int inEnd, int postStart, int postEnd );

输入说明 :

第一行:重构选择(0:前序中序重构  1:中序后序重构)  

0:

第二行:按前序遍历的结点序列,相邻结点用空格隔开

第三行:按中序遍历的结点序列,相邻结点用空格隔开

1:

第二行:按中序遍历的结点序列,相邻结点用空格隔开

第三行:按后序遍历的结点序列,相邻结点用空格隔开

输出说明 :

0:

第一行:按后序遍历的结点序列,相邻结点用","隔开

1:

第一行:按前序遍历的结点序列,相邻结点用","隔开

输入说明 :

第一行:重构选择(0:前序中序重构  1:中序后序重构)  

0:

第二行:按前序遍历的结点序列,相邻结点用空格隔开

第三行:按中序遍历的结点序列,相邻结点用空格隔开

1:

第二行:按中序遍历的结点序列,相邻结点用空格隔开

第三行:按后序遍历的结点序列,相邻结点用空格隔开

输出说明 :

0:

第一行:按后序遍历的结点序列,相邻结点用","隔开

1:

第一行:按前序遍历的结点序列,相邻结点用","隔开

-----------

0
A B C D E
B D C E A

----------------

D,E,C,B,A
 

#include<iostream>
#include<vector>
#include<string>
using namespace std;

template <class ElemType>
struct BiNode
{
    ElemType data;
    BiNode<ElemType> *left;
    BiNode<ElemType> *right;
};

template <class ElemType>//输入处理函数,考虑到不知道要输入多少字符,使用getline()函数全部读取后,按空格进行拆分,再压入vector
void input_handle(string str, vector<ElemType> &x)
{
    int len = str.length();
    string str0 = "";
    for (int i = 0; i < len; i++)
    {

        if (str[i] != ' ')
        {
            str0 += str[i];
        }

        else
        {
            x.push_back(str0);
            str0 = "";
        }
    }
    x.push_back(str0);
}

bool output_flag=false;

template <class ElemType>//后序遍历输出
void post_visit(BiNode<ElemType> *head)
{
    if (head->left)
       post_visit(head->left);

    if (head->right)
        post_visit(head->right);

    if (head && output_flag==0)
    {
        cout << head->data;
        output_flag=true;
    }
    else
    {cout << "," << head->data;}
}

template <class ElemType>
void pre_visit(BiNode<ElemType> *head)
{
    if (head && output_flag==0)
    {
        cout << head->data;
        output_flag=true;
    }
    else
    {cout << "," << head->data;}

    if (head->left)
       pre_visit(head->left);
    if (head->right)
        pre_visit(head->right);
}

template <class ElemType>
BiNode<ElemType> *reBuild_Pre_In(vector<ElemType> &preorder, vector<ElemType> &inorder)
{
    if(preorder.size()==0)
    {return NULL;}

    BiNode<ElemType> * Rebuild= new BiNode<ElemType>;
    Rebuild->data=preorder[0];

    int root_position=0;

    int inorder_len=inorder.size();

    vector<ElemType> left_pre, right_pre, left_in, right_in;

    for (int i = 0; i < inorder_len; i++)//在中序遍历中寻找根节点的位置
    {
        if (preorder[0] == inorder[i])
        {
            root_position = i;
            break;
        }
    }

    for (int i = 0; i < root_position; i++)//创建左子树的先序和中序序列,准备递归
    {
        left_in.push_back(inorder[i]);       //中序遍历,根结点之前全是左子树
        left_pre.push_back(preorder[i + 1]); //先序遍历,第一个是根节点,往后读取相同数量放入左子树
    }
    for (int i = root_position + 1; i < inorder_len; i++)//创建右子树的先序和中序序列,准备递归
    {
        right_in.push_back(inorder[i]);
        right_pre.push_back(preorder[i]);
    }

    Rebuild->left  =  reBuild_Pre_In(left_pre, left_in);    //递归创建左子树
    Rebuild->right =  reBuild_Pre_In(right_pre, right_in); //递归创建右子树

    return Rebuild;
}


template <class ElemType>
BiNode<ElemType> *reBuild_In_Post(vector<ElemType> & inorder, vector<ElemType> & postorder)
{
    if(postorder.size()==0)
    {return NULL;}

    int post_len=postorder.size();


    BiNode<ElemType> * Rebuild= new BiNode<ElemType>;
    Rebuild->data=postorder[post_len-1];

    vector<ElemType> left_in, right_in, left_post, right_post;

    int root_position = 0;

    int inorder_len=inorder.size();

    for (int i = 0; i < inorder_len; i++)//在中序遍历中寻找根节点的位置
    {
        if (postorder[post_len-1] == inorder[i])
        {
            root_position = i;
            break;
        }
    }

    for (int i = 0; i < root_position; i++)
    {
        left_in.push_back(inorder[i]);
        left_post.push_back(postorder[i]);
    }

    for (int i = root_position + 1; i < inorder_len; i++)
    {
        right_in.push_back(inorder[i]);
        right_post.push_back(postorder[i - 1]);
    }

    Rebuild->left  =  reBuild_In_Post(left_in,left_post );    //递归创建左子树
    Rebuild->right =  reBuild_In_Post( right_in,right_post); //递归创建右子树

    return Rebuild;
}



int main()
{
int flag;
cin>>flag;

getchar();//cin不会读入换行符,这里需要把换行符读掉,否则后面getline只会读入一个换行符
string a,b;
vector<string>first,second;

getline(cin,a);
input_handle(a,first);

getline(cin,b);
input_handle(b,second);

    BiNode<string> *root = new BiNode<string>;

if(flag==0)
    {
      root = reBuild_Pre_In(first, second);
      post_visit(root);
    }

else if(flag==1)
    {
        root = reBuild_In_Post(first, second);
        pre_visit(root);
    }

    return 0;

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值