二叉树:已知先序和中序求后序

本文介绍了一种利用递归思想根据先序遍历和中序遍历构建二叉树的方法,并提供了完整的C++实现代码。通过寻找根节点并划分左右子树,实现了二叉树的重建。

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

采用了递归的思想来解决问题。

先序遍历的第一个结点为该二叉树的根节点。

找到中序遍历中该根节点所在位置,则根节点左侧为该二叉树的左子树的中序遍历(右侧为二叉树的右子树的中序遍历),我们同时也得到了左子树的结点个数。

那么先序遍历去掉第一个结点,数出左子树结点个数个结点,便得到该二叉树左子树的先序遍历(剩下的为二叉树的右子树的先序遍历)。


程序的实现过程中,在Node中定义了一个建立二叉树的方法,三个参数分别为先序遍历字符串,中序遍历字符串,字符串长度。

过程是,创建当前节点p,赋值为先序遍历字符串首字符,判断左非空建立左子树,判断右非空建立右子树,返回该结点。

而后在BinaryTree中对root调用该方法,三个参数相同,返回给root。


#include<iostream>
#include<string>
using std::cout;
using std::endl;
using std::string;
class Node {
public:
    int data;
    Node *lchild, *rchild;
    Node(int _data) {
        data = _data;
        lchild = NULL;
        rchild = NULL;
    }
    ~Node() {
        if (lchild != NULL) {
            delete lchild;
        }
        if (rchild != NULL) {
            delete rchild;
        }
    }
    void postorder() {
        if (lchild != NULL) {
            lchild->postorder();
        }
        if (rchild != NULL) {
            rchild->postorder();
        }
        cout << data << " ";
    }
    // 请在下面实现建立二叉树的方法 build
    Node* build(const string &pre_str, const string &in_str, int len) {
        Node *p = new Node(pre_str[0] - '0');
        int pos = in_str.find(pre_str[0]);
        if (pos > 0) {
            p -> lchild = build(pre_str.substr(1, pos), in_str.substr(0, pos), pos);
        }
        if (len - pos - 1 > 0) {
            p -> rchild = build(pre_str.substr(pos + 1), in_str.substr(pos + 1), len - pos - 1);
        }
        return p;
    }
};
class BinaryTree {
private:
    Node *root;
public:
    BinaryTree() {
        root = NULL;
    }
    ~BinaryTree() {
        delete root;
    }
    // 请在下面实现构造函数
    BinaryTree(const string &pre_str, const string &in_str, int len) {
        root = root -> build(pre_str, in_str, len);
    }
    void postorder() {
        root->postorder();
    }
};
int main() {
    string pre_str = "136945827";
    string in_str = "963548127";
    BinaryTree binarytree(pre_str, in_str, in_str.length());
    binarytree.postorder();
    cout << endl;
    return 0;
}
<think>首,用户的问题是:“我想根据已知遍历遍历结果,出对应的后序遍历结果 请问如何从遍历遍历推导出后序遍历”。 我需要根据系统指令来构建回答: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 参考提供的引用: - 引用[1]:讨论了从二叉树的中后序推导,但用户需要的是从推导后序。 - 引用[2]:提到已知/后序与中出后/,但描述简略。 - 引用[3]:解释了二叉树遍历。 - 引用[4]:包含代码示例,但可能与问题相关。 用户的问题是从遍历遍历推导后序遍历。所以,我需要解释这个过程。 关键点: - 遍历(Preorder):根节点 -> 左子树 -> 右子树 - 中遍历(Inorder):左子树 -> 根节点 -> 右子树 - 后序遍历(Postorder):左子树 -> 右子树 -> 根节点 推导步骤: 1. 从遍历中,第一个元素是根节点。 2. 在中遍历中,找到根节点,根节点左边的元素是左子树的中遍历,右边是右子树的中遍历。 3. 根据左子树的大小,在遍历中分割出左子树的遍历右子树的遍历。 4. 递归地对左子树右子树应用相同过程。 5. 构建后序遍历左子树的后序,然后右子树的后序,最后根节点。 例如,假设: - :A B D E C F - 中:D B E A F C 步骤: 1. 第一个是A,所以根是A。 2. 中中,A左边是D B E(左子树),右边是F C(右子树)。 3. 左子树的:从中,A之后的下三个元素(因为左子树有3个节点),所以B D E。 4. 右子树的:剩下的C F。 5. 递归: - 左子树: B D E,中 D B E - 根是B,中中B左边是D(左子树),右边是E(右子树)。 - 左子树的后序:D(单节点) - 右子树的后序:E(单节点) - 所以左子树的后序:D E B - 右子树: C F,中 F C - 根是C,中中C左边是F(左子树) - 左子树的后序:F - 所以右子树的后序:F C 6. 整个树的后序:左子树后序 + 右子树后序 + 根 = D E B F C A 所以后序:D E B F C A 在回答中,我需要结构化: - 解释基础概念。 - 逐步描述方法。 - 可能给出一个简单例子。 - 确保使用正确的LaTeX格式。 - 生成相关问题。 生成相关问题: - 基于主题,例如:如何验证结果?处理边界情况?时间复杂度?优化方法?应用场景? 引用标识:在回答中,如果提到参考内容,自然地添加引用。例如,引用[3]解释了遍历,所以我可以说“如引用[3]所述”。 最终回答结构: 1. 介绍二叉树遍历基础。 2. 解释推导步骤。 3. 给出一个例子。 4. 总结。 5. 生成相关问题。</think>### 从遍历遍历推导后序遍历二叉树遍历中,已知遍历(Preorder)遍历(Inorder)列,可以唯一确定二叉树的结构,进而推导出后序遍历(Postorder)列。二叉树遍历定义如下: - **遍历**:根节点 → 左子树 → 右子树(例如:$A, B, C$ 表示根为 $A$,左子树为 $B$,右子树为 $C$)。 - **中遍历**:左子树 → 根节点 → 右子树(例如:$B, A, C$ 表示左子树为 $B$,根为 $A$,右子树为 $C$)。 - **后序遍历**:左子树 → 右子树 → 根节点(例如:$B, C, A$ 表示左子树为 $B$,右子树为 $C$,根为 $A$)。 推导后序遍历的核心思想是利用遍历确定根节点,然后通过中遍历分割左右子树,最后递归构建子树并组合结果[^3]。以下是详细步骤: #### 推导步骤 1. **识别根节点**: 遍历的第一个元素总是整棵树的根节点。例如,给定列 $P = [p_1, p_2, \dots, p_n]$,根节点为 $p_1$。 2. **分割中列**: 在中遍历列 $I = [i_1, i_2, \dots, i_n]$ 中找到根节点 $p_1$ 的位置 $k$(即 $i_k = p_1$)。 - 根节点左边的子列 $I_{\text{left}} = [i_1, \dots, i_{k-1}]$ 是左子树的中遍历。 - 根节点右边的子列 $I_{\text{right}} = [i_{k+1}, \dots, i_n]$ 是右子树的中遍历。 3. **分割列**: 根据左子树的大小(即 $I_{\text{left}}$ 的长度 $L$),分割列: - 左子树的遍历:$P_{\text{left}} = [p_2, p_3, \dots, p_{L+1}]$(跳过根节点后,取前 $L$ 个元素)。 - 右子树的遍历:$P_{\text{right}} = [p_{L+2}, \dots, p_n]$(剩余元素)。 4. **递归构建子树**: 对左子树 $(P_{\text{left}}, I_{\text{left}})$ 右子树 $(P_{\text{right}}, I_{\text{right}})$ 递归应用上述步骤,得到左子树的后序遍历 $L_{\text{post}}$ 右子树的后序遍历 $R_{\text{post}}$。 5. **组合后序列**: 后序遍历列为左子树后序 + 右子树后序 + 根节点,即: $$ \text{Postorder} = L_{\text{post}} + R_{\text{post}} + [p_1] $$ 其中 $+$ 表示列连接。 #### 示例 假设给定: - 遍历:$P = [A, B, D, E, C, F]$ - 中遍历:$I = [D, B, E, A, F, C]$ 逐步推导: 1. **根节点**:第一个元素 $A$ 是根。 2. **分割中**:在中中找到 $A$,位置 $k=4$(索引从1开始)。 - 左子树中:$I_{\text{left}} = [D, B, E]$($A$ 左边) - 右子树中:$I_{\text{right}} = [F, C]$($A$ 右边) 3. **分割**:左子树大小 $L=3$($I_{\text{left}}$ 长度)。 - 左子树:$P_{\text{left}} = [B, D, E]$(跳过 $A$,取前3个) - 右子树:$P_{\text{right}} = [C, F]$(剩余元素) 4. **递归左子树**:$(P_{\text{left}} = [B, D, E], I_{\text{left}} = [D, B, E])$ - 根节点:$B$ - 中分割:$B$ 左边 $[D]$(左子树),右边 $[E]$(右子树) - 分割:左子树 $[D]$,右子树 $[E]$ - 递归结果:左子树后序 $[D]$,右子树后序 $[E]$,组合为 $[D, E, B]$ 5. **递归右子树**:$(P_{\text{right}} = [C, F], I_{\text{right}} = [F, C])$ - 根节点:$C$ - 中分割:$C$ 左边 $[F]$(左子树) - 分割:左子树 $[F]$ - 递归结果:左子树后序 $[F]$,组合为 $[F, C]$(无右子树) 6. **组合后序**:左子树后序 $[D, E, B]$ + 右子树后序 $[F, C]$ + 根 $A$ = $[D, E, B, F, C, A]$ 因此,后序遍历结果为 $[D, E, B, F, C, A]$。此方法的时间复杂度为 $O(n^2)$(最坏情况需线性搜索中位置),可通过哈希表优化到 $O(n)$[^2]。 #### 注意事项 - **唯一性**:二叉树必须无重复节点值,否则列可能对应多个树。 - **边界处理**:当子树为空时(列长度为0),直接返回空列。 - **验证**:推导后,可用中后序重建树来验证正确性,如引用[4]中的代码示例。 此方法基于二叉树遍历的递归特性,确保每一步都缩小问题规模[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值