根据中序和前序遍历重建二叉树

重建二叉树

这里写图片描述

我们知道,前序遍历是先访问root,再依次访问左子树和右子树,而中序遍历则是先访问左子树,再依次访问root和右子树。在前序遍历中,第一个总为当前树的根节点root,因此我们可以根据root值在中序遍历序列中划分左右子树。然后再在划分的左右序列中,重复该操作,最终可以得到我们想要的结果。
我们以上面的前序和中序序列为例:

第一次:
在前序遍历,得到1为根节点,根据中序序列,得到4,7,2为左子树,5,3,8,6为右子树。

1

第二次:
我们此时先看左子树,在前序遍历中,得到2为根节点,根据中序序列,得到4,7为左子树,右子树为空。

这里写图片描述

第三次:
我们继续看左子树,在前序遍历中,得到4为根节点,根据中序遍历,7在4的右边,所以7为右子树,4前面没有了,因此左子树为空,到这一步我们把这棵树的左子树序列已经得到了。

这里写图片描述

接下来,我们根据相同的原理可以得到右子树,最终这棵树的样子就可以得到了,如下图:

这里写图片描述

在上例中,我们都是先根据当前前序遍历的结果得到根节点,再根据根节点在当前中序遍历序列中的位置划分左右子树。
然后在左子树中根据前序遍历的结果得到根节点,再根据根节点在中序遍历序列中的位置划分左右子树这样的一个递归过程完成树的构建。因此我们根据上述原理写出如下的递归代码:

struct Node //定义树的结点和构造函数
{
    int _data;
    Node *_left;
    Node *_right;
    Node(int x)
        : _data(x)
        , _left(NULL)
        , _right(NULL)
    {}
};

Node* _CBT(int* preStart, int* preEnd, int* inStart, int* inEnd)
{
    //根据先序序列得到当前的根节点
    int rootValue = preStart[0];
    Node *root = new Node(rootValue);
    //如果此时先序和中序只有一个结点
    if (preStart == preEnd)
    {
        if (inStart == inEnd && *preStart == *inEnd)
            return root;
        else//判错处理
        {
            cerr << "invalid input" << endl;
            exit(1);
        }
    }
    //根据根节点值找到它在中序序列的位置
    int *inRoot = inStart;
    while (inRoot <= inEnd && (*inRoot != rootValue))
        ++inRoot;
    //找不到的话说明输入有错
    if (inRoot == inEnd && (*inRoot != rootValue))
    {
        cerr << "invalid input" << endl;
        exit(1);
    }
    //划分左右子树
    int leftLen = inRoot - inStart;
    int rightLen = inEnd - inRoot;
    if (leftLen > 0)
        root->_left = _CBT(preStart + 1, preStart + leftLen, inStart, inStart + leftLen - 1);
    if (rightLen > 0)
        root->_right = _CBT(preStart + leftLen + 1, preEnd, inStart + leftLen + 1 , inEnd);
    return root;
}

Node *CreateBinaryTree(int *pre, int *in, int len)
{
    if (pre == NULL || in == NULL || len <= 0)
        return NULL;
    return _CBT(pre, pre + len - 1, in, in + len - 1);
}

完整的代码以及测试各种情况点击我的github_6_ConstructBinaryTree查看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值