• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
myInception
博客园    首页    新随笔    联系   管理    订阅  订阅
已知前、中、后序中两种遍历结果以重建二叉树

当知道前序遍历、中序遍历、后序遍历中的两种遍历方式,就能够反推出二叉树的结构了。
但是要注意一点:已知前序遍历&后序遍历结果时,二叉树不能有节点的度为1!!!
提醒: 此处默认二叉树节点存储的值为int类型,其他类型,如char等可以将vector换为string等
例题:遍历问题,美国血统

一、已知前&中序遍历结果

// 对应洛谷:https://www.luogu.com.cn/problem/P1827
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

struct Node
{
    int val;
    Node *l, *r;

    Node(int x) : val(x), l(nullptr), r(nullptr) {}
};

class BinaryTreeBuilder
{
private:
    unordered_map<int, int> inorderMap; // 存储中序遍历中各元素的索引位置
    int preorderIndex;                  // 前序遍历的当前索引

public:
    // 主函数,依据中序与前序遍历构建二叉树
    Node* buildTree(vector<int>& preorder, vector<int>& inorder)
    {
        for (int i = 0; i < (int)inorder.size(); i++) inorderMap[inorder[i]] = i;
        preorderIndex = 0;
        return buildHelper(preorder, 0, inorder.size()-1);
    }

private:
    // 递归辅助函数
    Node* buildHelper(vector<int>& preorder, int inorderStart, int inorderEnd)
    {
        if (inorderStart > inorderEnd) return NULL;
        // 前序遍历的当前元素即为根节点
        int rootVal = preorder[preorderIndex++];
        Node *root = new Node(rootVal);
        // 在中序遍历中找到根节点的位置
        int rootIdx = inorderMap[rootVal];
        // 构建左、右子树(递归)
        root->l = buildHelper(preorder, inorderStart, rootIdx-1); // 中序遍历中在根节点前的都属于左子树
        root->r = buildHelper(preorder, rootIdx+1, inorderEnd);   // 在后面的是右子树部分

        return root;
    }

public:
    // 销毁树
    void destroyTree(Node *root)
    {
        if (root == NULL) return;
        destroyTree(root->l);
        destroyTree(root->r);
        delete root;
    }

    // 中序遍历验证(左-根-右)
    void inOrder(Node *root)
    {
        if (root == NULL) return;
        inOrder(root->l);
        cout << root->val << " ";
        inOrder(root->r);
    }
    
    // 前序遍历验证(根-左-右)
    void preOrder(Node *root)
    {
        if (root == NULL) return;
        cout << root->val << " ";
        preOrder(root->l);
        preOrder(root->r);
    }
    
    // 后序遍历(左-右-根)
    void postOrder(Node *root)
    {
        if (root == NULL) return;
        postOrder(root->l);
        postOrder(root->r);
        cout << root->val << " ";
    }
};

int main()
{
    // 示例:根据给定的中序和前序遍历构建二叉树
    vector<int> preorder = {3, 9, 20, 15, 7};  // 前序遍历结果
    vector<int> inorder = {9, 3, 15, 20, 7};   // 中序遍历结果
    
    BinaryTreeBuilder builder;
    Node* root = builder.buildTree(preorder, inorder);
    
    cout << "构建的二叉树遍历结果:" << endl;
    cout << "前序遍历: ";
    builder.preOrder(root);
    cout << endl;
    
    cout << "中序遍历: ";
    builder.inOrder(root);
    cout << endl;
    
    cout << "后序遍历: ";
    builder.postOrder(root);
    cout << endl;

    builder.destroyTree(root);
    root = NULL;
    cout << "二叉树销毁完毕!" << endl;
    return 0;
}

二、已知前&后序遍历结果

注意:二叉树不能有节点的度为1!!!
遍历问题这道题是已知前、后序遍历求有多少种中序遍历结果,中序遍历中度等于1的节点是影响结果的因素,这个也是为什么在已知前、中、后序中两种遍历结果以重建二叉树中设置度不等于1。看了题解知道了一个知识点:前序中出现AB,后序中出现BA,则这个节点只有一个儿子。而这样的话只要找个度为1的节点数n,那么结果就是pow(2, n+1)。但是我们答题的时候一般使用找AB, BA的方法,使用substr(i, 2)截取AB,reverse得到BA,再find。

// 后序遍历的最后一个元素是根节点
// 但是这要求不能有度为1的节点(这不就是哈夫曼树嘛)
/*
解决方法:
1. 前序遍历的第一个元素是树的根节点
2. 后序遍历的最后一个元素也是树的根节点
3. 前序遍历中根节点之后的第一个元素通常是左子树的根节点(如果存在左子树)
4. 在后序遍历中找到这个左子树根节点的位置,就可以划分左右子树的范围
*/
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

struct Node
{
    int val;
    Node *l, *r;

    Node(int x) : val(x), l(nullptr), r(nullptr) {}
};

class BuildTree
{
private:
    unordered_map<int, int> postorderMap;
    int preorderIndex;

public:
    Node *build(vector<int> preorder, vector<int> postorder)
    {
        for (int i = 0; i < (int)postorder.size(); i++) postorderMap[postorder[i]] = i;
        preorderIndex = 0;
        return buildHelper(preorder, 0, postorder.size()-1);
    }

private:
    Node *buildHelper(vector<int> preorder, int postStart, int postEnd)
    {
        if (postStart > postEnd || preorderIndex >= (int)preorder.size()) return NULL;

        int rootVal = preorder[preorderIndex++];
        Node *root = new Node(rootVal);

        if (postStart == postEnd) return root; // 只有一个节点,则直接返回

        // 在后序遍历中找到左子树根节点的位置
        int lRootVal = preorder[preorderIndex];
        int lRootIdx = postorderMap[lRootVal];

        root->l = buildHelper(preorder, postStart, lRootIdx);
        root->r = buildHelper(preorder, lRootIdx+1, postEnd-1);

        return root;
    }

public:
    // 销毁树
    void destroyTree(Node *root)
    {
        if (root == NULL) return;
        destroyTree(root->l);
        destroyTree(root->r);
        delete root;
    }

    // 中序遍历验证(左-根-右)
    void inOrder(Node *root)
    {
        if (root == NULL) return;
        inOrder(root->l);
        cout << root->val << " ";
        inOrder(root->r);
    }
    
    // 前序遍历验证(根-左-右)
    void preOrder(Node *root)
    {
        if (root == NULL) return;
        cout << root->val << " ";
        preOrder(root->l);
        preOrder(root->r);
    }
    
    // 后序遍历(左-右-根)
    void postOrder(Node *root)
    {
        if (root == NULL) return;
        postOrder(root->l);
        postOrder(root->r);
        cout << root->val << " ";
    }
};

int main()
{
    // 示例:根据给定的前序和后序遍历构建二叉树
    vector<int> preorder = {1, 2, 4, 5, 3, 6, 7};   // 前序遍历结果
    vector<int> postorder = {4, 5, 2, 6, 7, 3, 1};  // 后序遍历结果
    
    BuildTree builder;
    Node* root = builder.build(preorder, postorder);
    
    cout << "根据前序和后序遍历重建的二叉树:" << endl;
    cout << "前序遍历: ";
    builder.preOrder(root);
    cout << endl;
    
    cout << "中序遍历: ";
    builder.inOrder(root);
    cout << endl;
    
    cout << "后序遍历: ";
    builder.postOrder(root);
    cout << endl;
    
    // 释放内存
    builder.destroyTree(root);
    root = nullptr;
    
    cout << "二叉树内存已释放!" << endl;

    return 0;
}

三、已知中&后序遍历结果

// 这个和已知前&中差不多,因为只要找到根节点——后序遍历的最后一个元素,再将中序遍历中左右子树(根节点的前后)递归创建拼接即可
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

struct Node
{
    int val;
    Node *l, *r;

    Node(int x) : val(x), l(nullptr), r(nullptr) {}
};

class Tree
{
private:
    unordered_map<int, int> inorderMap;
    int postorderIndex;

public:
    Node *build(vector<int> inorder, vector<int> postorder)
    {
        for (int i = 0; i < (int)inorder.size(); i++) inorderMap[inorder[i]] = i;
        postorderIndex = postorder.size() - 1;
        return buildHelper(postorder, 0, inorder.size()-1);
    }

private:
    Node *buildHelper(vector<int> postorder, int inorderStart, int inorderEnd)
    {
        if (inorderStart > inorderEnd) return NULL;

        int rootVal = postorder[postorderIndex--];
        Node *root = new Node(rootVal);

        int rootIdx = inorderMap[rootVal];

        root->r = buildHelper(postorder, rootIdx+1, inorderEnd);
        root->l = buildHelper(postorder, inorderStart, rootIdx-1);

        return root;
    }

public:
    // 销毁树
    void destroyTree(Node *root)
    {
        if (root == NULL) return;
        destroyTree(root->l);
        destroyTree(root->r);
        delete root;
    }

    // 中序遍历验证(左-根-右)
    void inOrder(Node *root)
    {
        if (root == NULL) return;
        inOrder(root->l);
        cout << root->val << " ";
        inOrder(root->r);
    }
    
    // 前序遍历验证(根-左-右)
    void preOrder(Node *root)
    {
        if (root == NULL) return;
        cout << root->val << " ";
        preOrder(root->l);
        preOrder(root->r);
    }
    
    // 后序遍历(左-右-根)
    void postOrder(Node *root)
    {
        if (root == NULL) return;
        postOrder(root->l);
        postOrder(root->r);
        cout << root->val << " ";
    }
};

int main()
{
    // 示例:根据给定的中序和前序遍历构建二叉树
    vector<int> preorder = {9, 3, 15, 20, 7};  // 中序遍历结果
    vector<int> inorder = {9, 15, 7, 20, 3};   // 后序遍历结果
    
    Tree builder;
    Node* root = builder.build(preorder, inorder);
    
    cout << "构建的二叉树遍历结果:" << endl;
    cout << "前序遍历: ";
    builder.preOrder(root);
    cout << endl;
    
    cout << "中序遍历: ";
    builder.inOrder(root);
    cout << endl;
    
    cout << "后序遍历: ";
    builder.postOrder(root);
    cout << endl;

    builder.destroyTree(root);
    root = NULL;
    cout << "二叉树销毁完毕!" << endl;

    return 0;
}
posted on 2026-03-09 13:28  myLv  阅读(1)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3