重建二叉树(根据先序遍历(或者后序遍历)和中序遍历重建二叉树)

本文深入探讨了如何使用先序、中序及后序遍历结果重构二叉树的算法,详细解释了先序遍历与中序遍历、后序遍历与中序遍历两种方式下重构树的具体步骤与代码实现。

先序遍历和中序遍历

1、先序遍历的结果中第一个元素一定是根节点
2、先序遍历结果= 根节点+左子树先序结构+右子树先序结果
3、中序遍历结果= 左子树的中序结果+根节点+右子树的中序结果

在这里插入图片描述

根据上图,3为根节点,根据中序遍历9是3的左子树而且只有一个节点,先序中9后面的20就是3的右子树的根节点,然后再看中序遍历,15在20的左侧7在20右侧,得15是20的左子树7是20的右子树。最后构建出的树如下图:
在这里插入图片描述
代码思路:
注:中序遍历数组中根节点的左边都是左子树的节点,根节点右边都是右子树节点
在这里插入图片描述
1、设置变量inedx 方便从preorder数组中从0号下标开始获取节点。
2、判断inedx的合法性,防止我们在最终的递归途中数组越界异常。
3、中序遍历中根结点可以作为一道分界线,左边是他的左子树结点,右边是右子树结点,所以一开始的inorderLeft 为0 而inorderRight为中序遍历数组的长度。
4、根结点就是先序遍历的第一个结点,构建根结点,然后index++(方法中index只加一次是因为在preorder数组中index下标的元素只可能是左结点或者右结点)
5、构建根结点的左子树,(在此之前我们要在中序遍历中找到根结点元素的下标pos),我们知道 中序遍历的序列组成可以表示为 :左子树结点+根结点+右子树结点 所以,根结点的左结点一定在pos之前。
6、然后我们进行递归进行判断inorderLeft 和inorderRight(就是上一个方法传来的pos值)的合法性,只要inorderLeft不是大于等于inorderRight 就说明在根结点下标的左边有元素,也就是说根结点的左子树不为空。
7、构建该结点然后再次进行递归判断,直到根结点的左子树的根结点建立完。此时就要建立根节点的子树、此时传入的inorderLeft为pos+1和一开始的inorderRight,然后进行递归处理,只要 inorderLeft不是大于等于inorderRight 就说明在根结点下标的右边有元素,也就是说明有右子树,之后进行构建。

    //preorder这个数组和inorder长度相同
    //用index记录访问到哪个节点,记录在preorder中访问到哪个元素
    private int index = 0;
    public TreeNode buildTree(int[] preorder, int[] inorder){
   
   
        index = 0;
        //借助buildTreeHelper方法进行递归
        //加入一对参数表示当前子树对应的中序遍历结果的区间。
        return buildTreeHelper(preorder,inorder,0,inorder.length);
    }
    //[inorderLeft,inorderRight)表示当前这个子树的中序遍历区间
        private TreeNode buildTreeHelper(int[] preorder, int[]
<think>嗯,用户的问题是根据二叉树序遍历来计算后序遍历。我需要回忆一下相关的二叉树遍历知识,然后思考如何通过这两种遍历结果来重建二叉树,进而得到后序遍历。 首序遍历的顺序是根节点、左子树、右子树,而中序遍历是左子树、根节点、右子树。所以,序遍历的第一个元素肯定是整个树的根节点。然后在中序遍历中找到这个根节点,左边就是左子树的中序遍历结果,右边是右子树的中序遍历结果。接下来,可以通过递归的方法分别处理左子树右子树。 举个例子,假设序是[3,9,20,15,7],中序是[9,3,15,20,7]。序的第一个元素3是根节点。在中序中,3左边的9是左子树的中序,右边的15,20,7是右子树的中序。然后,左子树的序应该是序中根之后的部分,长度中序左子树的长度相同,也就是9。右子树的序则是剩下的20,15,7。这样递归下去,就能重建整个二叉树的结构。重建之后再进行后序遍历,就能得到结果了。 不过要注意边界条件,比如当左子树或右子树为空的时候,递归应该停止。另外,如何高效地在中序遍历中找到根节点的位置?可能需要用哈希表来存储中序遍历的值索引,这样查找起来更快,时间复杂度更低。 用户可能还需要具体的实现步骤或者代码示例。根据引用的内容,比如引用[2]提到了递归非递归的实现方法,但这里可能需要用递归来重建二叉树,然后再进行后序遍历。所以代码部分应该包括构建二叉树后续遍历两个部分。 还需要考虑输入的有效性,比如序遍历的长度是否一致,以及是否确实对应同一棵树。如果输入不合法,比如无法构建二叉树,应该如何处理这些错误情况。 另外,用户可能想知道时间复杂度空间复杂度。构建哈希表是O(n)的时间,递归重建二叉树每个节点访问一次,所以时间复杂度是O(n)。空间复杂度主要是递归栈的深度,最坏情况下是O(n),平均是O(log n)(平衡二叉树的情况下)。 最后,生成相关问题的时候,可以考虑其他遍历组合的可能性,或者如何优化算法,或者实际应用场景。</think>### 通过序遍历计算后序遍历的方法 通过二叉树序遍历序遍历推导后序遍历的核心步骤为: 1. **确定根节点**:序遍历的第一个元素即为根节点值 2. **划分左右子树**:在中序遍历中找到根节点,左侧为左子树的中序序列,右侧为右子树的中序序列 3. **递归构建子树**:根据左右子树的长度,分割序序列为左子树右子树序 4. **生成后序遍历**:递归完成后序遍历的拼接顺序为左子树后序 + 右子树后序 + 根节点 #### 算法实现(Python示例) ```python def build_tree(preorder, inorder): if not preorder or not inorder: return None root_val = preorder[0] root_idx = inorder.index(root_val) left_in = inorder[:root_idx] right_in = inorder[root_idx+1:] left_pre = preorder[1:1+len(left_in)] right_pre = preorder[1+len(left_in):] root = {'val': root_val} root['left'] = build_tree(left_pre, left_in) root['right'] = build_tree(right_pre, right_in) return root def postorder(root): if not root: return [] return postorder(root['left']) + postorder(root['right']) + [root['val']] # 示例输入 preorder = [3,9,20,15,7] inorder = [9,3,15,20,7] tree = build_tree(preorder, inorder) print("后序遍历结果:", postorder(tree)) # 输出: [9,15,7,20,3] ``` #### 关键说明 1. **时间复杂度**:$O(n^2)$(未使用哈希表优化),若用哈希表存储中序索引可优化至$O(n)$[^2] 2. **边界条件**:当中序序列不匹配时无法构建树(需额外校验) 3. **空间复杂度**:递归调用栈深度为树的高度,最坏情况下为$O(n)$[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值