重建二叉树

问题描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

函数接口: TreeNode* reConstructBinaryTree(vector pre,vector vin)

注意:不一定非要根据接口去写,自己能实现算法就可以了

解题方法
1.因为前序遍历的顺序就是按照根左右来创建的,所以参考前序遍历的顺序可以按照顺序来创建根结点,因为中序遍历的顺序是左根右,所以参考中序遍历的方法可以确定根节点的左子树和右子数,然后递归先创建左子树,然后创建右子树。
举个例子:
比如题中给出的数据
前序:1 2 4 7 3 5 6 8
中序:4 7 2 1 5 3 8 6
1.根据前序顺序首先根节点为1,所以在中序中找到1结点所在的位置,这个时候1结点左边的4 7 2 为根节点的左子树,右边的5 3 8 6为跟结点的右子数

2.根据前序根节点为2.找到中序中的2的位置,现在2的左边的4 7为2的左子树,因为1为根节点所以2没有右子数,

3.根据前序根节点为4,找到中序中4的位置。因为4的左边没有元素,所以4没有左子树,4的右边为7.所以4的右子数为7,这个时候整个树的左子树就出来了,如下图

这里写图片描述

下面开始创建根节点1的右子数
5.前序三为根节点,在中序中找到3的位置,所以5是3的左子树,8 6 是三的右子树

6.创建根节点5,5没有左右子树

7.创建根节点 6,在中序中找到6的位置,所以8是6的左子树,至此整个树就创建完成了。如下图

这里写图片描述

下面给出算法代码1:

        PNode _reConstructBinaryTree(vector<int> pre, vector<int> vin)//重建二叉树的接口
    {
        if (pre.empty()||vin.empty())
            return NULL;
        int data = pre.front();
        int n = vin.size();
        int lenth = 0;
        int index = 0;
        PNode cur = new Node(data);//创建根节点
        //下面开始在中序遍历中找根结点的左子树和右子数
        for (int i = 0; i < n; i++)
        {
            if (vin[i] == data)
            {
                index = i;//找到右子树中对应的位置
                lenth = n - i - 1;//记录中序遍历右子树的起点位置
                break;
            }
        }
        vector<int> preleft(pre.begin() + 1, pre.begin() + index+1);//记录左子树的前序遍历的顺序
        vector<int> vinleft(vin.begin(), vin.begin() + index);//记录左子树中序遍历的顺序
        vector<int> preright(pre.begin() +index+1, pre.begin()+lenth+index+1);//记录右子数的前序遍历顺序
        vector<int> vinright(vin.begin() +index+1, vin.begin() + lenth+index+1);//记录右子树的中序遍历顺序
        cur->Lchild = _reConstructBinaryTree(preleft, vinleft);
        cur->Rchild = _reConstructBinaryTree(preright, vinright);
        return cur;
    }

算法代码2:

PNode  _ConstructBinTree(int *preOrder, int *inOrder, int length)//重建二叉树
    {
        if (NULL == preOrder || NULL == inOrder || length <= 0)
            return NULL;
        int data = preOrder[0];
        PNode cur = new Node(data);
        int index = 0;
        int lenth = 0;
        for (int i = 0; i < length; i++)//根据中序找到根节点的左右子树
        {
            if (data == inOrder[i])
            {
                index = i;//根节点在中序中的位置
                lenth = length - i -1;
                break;
            }
        }
        int *preleft = preOrder + 1;//记录左子树前序
        int *inleft = inOrder;//记录左子树中序
        int *preright = preOrder + index + 1;//记录右子树前序
        int *inright = inOrder + index + 1;//记录右字树中序
        cur->Lchild = _ConstructBinTree(preleft, inleft, index);//创建左子树
        cur->Rchild = _ConstructBinTree(preright, inright, lenth);//创建右子数
        return cur;
    }

下面给出完整代码和测试结果:

#include<iostream>
#include<vector>
using namespace std;
template<class T>
struct BinTreeNode//二叉树的结点
{
    T _data;
    BinTreeNode<T> *Lchild;
    BinTreeNode<T> *Rchild;
    BinTreeNode(T& data)
        :_data(data)
        , Lchild(NULL)
        , Rchild(NULL){}
};
template<class T>
class TreeNode
{
    typedef BinTreeNode<T> *PNode;
    typedef BinTreeNode<T> Node;
public:
    PNode head;
    TreeNode()
        :head(NULL)
    {}

    void reConstructBinaryTree(vector<int> pre, vector<int> vin)//调用重建二叉树的函数
    {
        head = _reConstructBinaryTree(pre, vin);
    }
    void ConstructBinTree(int *preOrder, int *inOrder, int length)
    {
        head = _ConstructBinTree(preOrder, inOrder, length);
    }
private:
    PNode _reConstructBinaryTree(vector<int> pre, vector<int> vin)//重建二叉树的接口
    {
        if (pre.empty()||vin.empty())
            return NULL;
        int data = pre.front();
        int n = vin.size();
        int lenth = 0;
        int index = 0;
        PNode cur = new Node(data);//创建根节点
        //下面开始在中序遍历中找根结点的左子树和右子数
        for (int i = 0; i < n; i++)
        {
            if (vin[i] == data)
            {
                index = i;//找到右子树中对应的位置
                lenth = n - i - 1;//记录中序遍历右子树的起点位置
                break;
            }
        }
        vector<int> preleft(pre.begin() + 1, pre.begin() + index+1);//记录左子树的前序遍历的顺序
        vector<int> vinleft(vin.begin(), vin.begin() + index);//记录左子树中序遍历的顺序
        vector<int> preright(pre.begin() +index+1, pre.begin()+lenth+index+1);//记录右子数的前序遍历顺序
        vector<int> vinright(vin.begin() +index+1, vin.begin() + lenth+index+1);//记录右子树的中序遍历顺序
        cur->Lchild = _reConstructBinaryTree(preleft, vinleft);
        cur->Rchild = _reConstructBinaryTree(preright, vinright);
        return cur;
    }
    PNode  _ConstructBinTree(int *preOrder, int *inOrder, int length)//重建二叉树
    {
        if (NULL == preOrder || NULL == inOrder || length <= 0)
            return NULL;
        int data = preOrder[0];
        PNode cur = new Node(data);
        int index = 0;
        int lenth = 0;
        for (int i = 0; i < length; i++)//根据中序找到根节点的左右子树
        {
            if (data == inOrder[i])
            {
                index = i;//根节点在中序中的位置
                lenth = length - i -1;
                break;
            }
        }
        int *preleft = preOrder + 1;//记录左子树前序
        int *inleft = inOrder;//记录左子树中序
        int *preright = preOrder + index + 1;//记录右子树前序
        int *inright = inOrder + index + 1;//记录右字树中序
        cur->Lchild = _ConstructBinTree(preleft, inleft, index);//创建左子树
        cur->Rchild = _ConstructBinTree(preright, inright, lenth);//创建右子数
        return cur;
    }
};

int main()
{

    vector<int> pre = { 1, 2, 4, 7, 3, 5, 6, 8 };
    vector<int> vin = { 4, 7, 2, 1, 5, 3, 8, 6 };
    TreeNode<int> s1;
    TreeNode<int> s2;
    int pree[] = { 1, 2, 4, 7, 3, 5, 6, 8 };
    int vinn[] = { 4, 7, 2, 1, 5, 3, 8, 6 };
    s1.reConstructBinaryTree(pre, vin);
    s2.ConstructBinTree(pree, vinn, 8);
    system("pause");
    return 0;
}

结果如下:
这里写图片描述

这里只给出了s1的结果指向图,能做到这个题的应该懂这个图,这里就不多说了(直接去监视里面看就可以了,不懂的自己摸索),s2的自己去看看吧,两个结果是一样的,完整的创建了整个二叉树!

<think>嗯,用户想用C++实现重建二叉树的方法,特别是根据前序和中序遍历来构建。我需要参考提供的引用内容,特别是引用[2]和[4]中的代码示例。首先,我应该确认递归方法的步骤:前序的第一个元素是根节点,然后在中序中找到根的位置,分割左右子树,再递归处理左右子树。用户可能需要详细的步骤解释和代码示例,同时注意边界条件,比如空数组的情况。还要考虑代码的效率,比如使用哈希表来快速查找中序中的根节点位置,如引用[1]提到的indexMap。不过引用[2]中的代码用的是循环查找,可能需要优化。另外,引用[4]提到了递归的模板,可以按照这个结构来组织代码。最后,需要生成相关问题,比如优化方法或应用场景。确保代码正确,语法正确,并符合用户的要求。</think>### C++实现重建二叉树的方法 根据前序遍历和中序遍历重建二叉树的步骤如下: 1. **递归终止条件** 当前序遍历或中序遍历序列为空时返回空指针。 2. **确定根节点** 前序遍历序列的第一个元素为当前子树的根节点值,例如:$pre[0] = rootVal$[^3]。 3. **划分左右子树** 在中序遍历序列中找到根节点的位置$i$,则: - 左子树的中序遍历范围:$vin[0]$至$vin[i-1]$ - 右子树的中序遍历范围:$vin[i+1]$至$vin[end]$ 前序遍历序列根据中序划分结果计算左右子树范围[^4]。 4. **递归构建子树** 对左右子树的序列递归调用构建函数。 #### 代码实现(优化版) ```cpp #include <vector> #include <unordered_map> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; class Solution { public: unordered_map<int, int> indexMap; // 中序遍历值到索引的哈希表 TreeNode* buildTree(vector<int>& pre, int preStart, int preEnd, vector<int>& vin, int vinStart, int vinEnd) { if (preStart > preEnd || vinStart > vinEnd) return nullptr; int rootVal = pre[preStart]; TreeNode* root = new TreeNode(rootVal); int i = indexMap[rootVal]; // 直接通过哈希表查找位置 int leftSize = i - vinStart; root->left = buildTree(pre, preStart + 1, preStart + leftSize, vin, vinStart, i - 1); root->right = buildTree(pre, preStart + leftSize + 1, preEnd, vin, i + 1, vinEnd); return root; } TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) { if (pre.empty() || vin.empty()) return nullptr; for (int i = 0; i < vin.size(); i++) indexMap[vin[i]] = i; // 预存中序遍历索引 return buildTree(pre, 0, pre.size()-1, vin, 0, vin.size()-1); } }; ``` #### 关键改进说明 1. **哈希表优化**:通过预存中序遍历索引,将查找根节点位置的时间复杂度从$O(n)$降为$O(1)$[^1]。 2. **避免向量拷贝**:原代码通过向量切片传递参数(如`leftpre`),现改为传递索引范围,减少内存占用。 3. **边界条件处理**:明确递归终止条件,避免栈溢出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值