由前序和中序数组重建二叉树

本文介绍了一种通过前序和中序遍历结果重建二叉树的方法。利用递归思想,确定根节点,并划分左右子树,最终实现二叉树的重建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、重建二叉树
来源:牛客网

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

2、思路:先序第一个元素a为根节点,在中序数组中,a左边的元素为左子树,右边为右子树。左右子树放到递归中处理即可

3、代码:

private TreeNode conBinaryTreeByPreAndIn(TreeNode root, int[] pre, int[] in, int pre_start,
            int pre_end, int in_start, int in_end) {

        int i, in_pos = 0;
        // 找到先序中第一个元素在中序中的下标pos
        for (i = in_start; i <= in_end; i++) {
            if (in[i] == root.val) {
                in_pos = i;
                break;
            }
        }
        TreeNode leftNode = null, rightNode = null;
        int left_num = in_pos-in_start;//左子树数目

        // 当前根节点存在左子树
        if (in_pos > in_start) {
            leftNode = new TreeNode(pre[pre_start + 1]);
            root.left = leftNode;
        }
        // 当前根节点存在右子树
        if (in_pos < in_end) {
            rightNode = new TreeNode(pre[pre_start+(left_num+1)]);
            root.right = rightNode;
        }

        // 根节点左边子节点数大于1
        if (in_pos - in_start > 1) {
            conBinaryTreeByPreAndIn(leftNode, pre, in, pre_start + 1, pre_start + left_num,
                                             in_start , in_pos - 1);
        }
        // 根节点右边子节点数大于1
        if (in_end - in_pos > 1) {
            conBinaryTreeByPreAndIn(rightNode, pre, in, pre_start + left_num + 1, pre_end,
                                             in_pos + 1, in_end);
        }
        return root;
    }
<think>嗯,用户问的是如何用前序遍历重建二叉树。我得先回忆一下二叉树遍历的知识。前序遍历是根节点先访问,然后是左子树,再右子树。中遍历则是左子树先,根节点中间,右子树最后。所以重建的关键在于找到根节点,然后分割左右子树。 首先,前序数组的第一个元素就是根节点。然后在中序数中找到这个根节点的位置,左边就是左子树的中,右边是右子树的中。根据左子树的长度,可以在前序数组中确定左子树的前序部分右子树的前序部分。然后递归处理左右子树。 比如,前序是[3,9,20,15,7],中是[9,3,15,20,7]。根是3,在中里找到3的位置,左边9是左子树,右边15,20,7是右子树。前序中左子树部分应该是接下来的1个元素(因为左中长度是1),也就是9,剩下的20,15,7是右子树的前序。然后递归构建左右子树。 需要注意的点是,如何处理数组的索引。比如,确定左子树在前序中的起始结束位置。还有递归终止条件,当数组为空时返回nullptr。 另外,可能要考虑元素重复的情况,但题目一般假设没有重复。如果有重复的话,可能无法唯一确定树的结构。所以代码中需要假设元素唯一。 代码方面,可以用哈希表来存储中的值索引,方便快速查找根的位置。递归函数参数包括前序的当前根索引,中的左右边界。每次递归时,前序的根索引递增,比如用引用或指针来维护,或者在每次递归时计算新的根位置。比如,前序根的位置应该是当前根的下一个位置,左子树的根是当前根+1,右子树的根是当前根+左子树长度+1。 例如,递归函数可能的结构: TreeNode* build(vector<int>& pre, int& preIndex, unordered_map<int,int>& inMap, int inLeft, int inRight)。 在函数里,先取出前序的当前根值,创建节点。然后在中中找到该值的索引,分割左右子树。preIndex每次递归时递增,左子树处理完后,preIndex已经指向右子树的根的位置。 测试时需要注意各种情况,比如空树、单节点、只有左子树或右子树的情况。 可能的问题包括索引计算错误,比如左子树的长度应该是根在中中的位置减去左边界。递归终止条件是当inLeft > inRight时返回空指针。 综上,步骤大致是:哈希表中存中的值索引,递归构建,每次确定根节点,分割左右子树,递归处理左右。关键点在于正确计算左右子树的索引范围。</think><< 使用前序遍历重建二叉树的步骤如下: 1. **确定根节点**:前序遍历的第一个元素即为当前子树的根节点 2. **分割中序数**:在中遍历中找到根节点位置,左边为左子树,右边为右子树 3. **递归构建子树**:根据左右子树的节点数量,在前序遍历中分割对应的左右子树列 示例代码实现: ```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: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { unordered_map<int, int> inMap; for (int i = 0; i < inorder.size(); i++) inMap[inorder[i]] = i; int preIndex = 0; return build(preorder, preIndex, inMap, 0, inorder.size()-1); } private: TreeNode* build(vector<int>& pre, int& preIndex, unordered_map<int,int>& inMap, int inLeft, int inRight) { if (inLeft > inRight) return nullptr; int rootVal = pre[preIndex++]; TreeNode* root = new TreeNode(rootVal); int inIndex = inMap[rootVal]; root->left = build(pre, preIndex, inMap, inLeft, inIndex-1); root->right = build(pre, preIndex, inMap, inIndex+1, inRight); return root; } }; ``` **实现原理**: 1. 使用哈希表存储中遍历的值与索引的对应关系,实现O(1)时间查找根节点位置 2. 前序遍历索引通过引用传递维护递归过程中的当前节点位置 3. 通过递归不断划分左右子树的范围: - 左子树范围:中起始位置到根节点位置-1 - 右子树范围:根节点位置+1到中结束位置 **时间复杂度**:O(n) 每个节点处理一次 **空间复杂度**:O(n) 哈希表存储中索引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值