前序中序画树、后序中序画树、前序后序画树

一、理解前序、中序、后序:

        说白了前序、中序、后序,就是看你在遍历树的时候是选择将根放在前、中、后的哪个位置

        前序:“根左右”

        中序:“左根右”

        后序:“左右根”

  • 前序遍历常用于复制树或在树中找节点。

  • 中序遍历通常用于获取排序的节点值(对于二叉搜索树)。

  • 后序遍历常用于删除树或计算树的高度。

        1、前序:

/*二叉树的前序遍历递归算法*/
void PreOderTraverse(BiTree T)
{
    if (T == NULL)
        return ;
    cout << T->data;            /*显示结点数据*/
    PreOderTraverse(T->lchild); /*再先序遍历左子树*/
    PreOderTraverse(T->rchild); /*最后先序遍历右子树*/
}

        2、中序:

/*二叉树的中序遍历递归算法*/
void InOrderTraverse(BiTree T)
{
    if (T == NULL)
        return;
    InOrderTraverse(T->lchild); /*中序遍历左子树*/
    cout << T->data;            /*显示结点数据*/
    InOrderTraverse(T->rchild); /*最后中序遍历右子树*/
}

        3、后序:

/*二叉树的后序遍历递归算法*/
void PostOrderTraverse(BiTree T)
{
    if (T == NULL)
        return;
    PostOrderTraverse(T->lchild); /*先后序遍历左子树*/
    PostOrderTraverse(T->lchild); /*在后序遍历右子树*/
    cout << T->data;              /*显示结点数据*/
}

二、前序中序画树:

        通过结合前序和中序遍历的信息,这段代码能够有效地构建出对应的二叉树。前序遍历提供了根节点的顺序,而中序遍历则提供了左右子树的结构信息。

  • 前序遍历 (preorder): 访问根节点,然后访问左子树,最后访问右子树。

  • 中序遍历 (inorder): 先访问左子树,然后访问根节点,最后访问右子树。

  • 使用 unordered_map<int, int> index 来存储中序遍历中每个节点值的索引,以便快速查找。

  • 使用 int pre 作为前序遍历中当前节点的索引。

  • 构建树的递归函数 buildTree_func:

    • 基线条件: 当左边界大于右边界时,返回 nullptr,表示当前子树为空。

    • 从前序遍历中获取根节点值,并更新 pre 指针。

    • 根据根节点值在中序遍历中找到对应的索引 i,这将帮助确定左子树和右子树的范围。

    • 创建当前根节点。

    • 递归调用自身来构建左子树和右子树:

      • 左子树范围是 [left, i - 1]

      • 右子树范围是 [i + 1, right]

class Solution {
    // 用于存储中序遍历中每个值的索引
    unordered_map<int, int> index;
    // 前序遍历的当前索引
    int pre = 0;

public:
    // 递归构建二叉树的辅助函数
    TreeNode* buildTree_func(vector<int>& preorder, vector<int>& inorder, int left, int right) {
        // 如果左指针大于右指针,说明已经没有节点可构建,返回 nullptr
        if (left > right)
            return nullptr;

        // 获取前序遍历中的根节点值,并更新 pre 指针
        int root_val = preorder[pre++];
        // 在中序遍历中找到根节点的索引
        int i = index[root_val];
        
        // 创建当前根节点
        TreeNode* node = new TreeNode(root_val);
        
        // 递归构建左子树,范围是左边界到根节点索引-1
        node->left = buildTree_func(preorder, inorder, left, i - 1);
        // 递归构建右子树,范围是根节点索引+1到右边界
        node->right = buildTree_func(preorder, inorder, i + 1, right);
        
        // 返回构建的节点
        return node;
    }

public:
    // 主函数,构建二叉树
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = inorder.size();
        // 将中序遍历的值及其索引存入哈希表
        for (int i = 0; i < n; i++) {
            index[inorder[i]] = i;
        }
        // 调用辅助函数,开始构建树,初始范围是整个中序数组
        return buildTree_func(preorder, inorder, 0, n - 1);
    }
};

三、后序中序画树:

        通过结合中序遍历和后序遍历的信息,这段代码能够有效地构建出对应的二叉树。后序遍历提供了根节点的顺序,而中序遍历则提供了左右子树的结构信息。

  • 中序遍历 (inorder): 先访问左子树,再访问根节点,最后访问右子树。

  • 后序遍历 (postorder): 先访问左子树,然后访问右子树,最后访问根节点。

  • 使用 unordered_map<int, int> index 来存储中序遍历中每个节点值的索引,方便快速查找。

  • 使用 int& post 作为后序遍历中当前节点的索引,从后往前进行访问。

  • 递归构建树的辅助函数 buildTree_func:

    • 基线条件: 当左边界大于右边界时,返回 nullptr,表示当前子树为空。

    • 从后序遍历中获取当前子树的根节点值,并将 post 指针向前移动。

    • 根据根节点值在中序遍历中找到其索引 i,这帮助我们确定左子树和右子树的范围。

    • 创建当前根节点。

    • 递归调用自身来构建右子树和左子树:

      • 右子树的范围是 [i + 1, right]

      • 左子树的范围是 [left, i - 1]

    • 返回创建的节点。

class Solution {
    // 用于存储中序遍历中每个节点值的索引
    unordered_map<int, int> index;

    // 递归构建二叉树的辅助函数
    // 使用后序遍历和中序遍历来构建
    TreeNode* buildTree_func(vector<int>& inorder, vector<int>& postorder, int left, int right, int& post) {
        // 如果左边界大于右边界,说明当前子树为空,返回 nullptr
        if (left > right) return nullptr;

        // 从后序遍历中获取当前子树的根节点值,并更新 post 指针
        int root_val = postorder[post--];

        // 在中序遍历中找到根节点的索引
        int i = index[root_val];

        // 创建当前根节点
        TreeNode* node = new TreeNode(root_val);

        // 注意:后序遍历的顺序是左子树、右子树、根节点
        // 但由于我们是从后往前取后序遍历的节点,所以先构建右子树,再构建左子树
        node->right = buildTree_func(inorder, postorder, i + 1, right, post);
        node->left = buildTree_func(inorder, postorder, left, i - 1, post);

        // 返回构建的节点
        return node;
    }

public:
    // 主函数,构建二叉树
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int n = inorder.size();
        
        // 将中序遍历中的节点值及其索引存入哈希表
        for (int i = 0; i < n; i++) {
            index[inorder[i]] = i;
        }

        // post 初始化为后序遍历的最后一个索引
        int post = n - 1;

        // 调用辅助函数,开始构建树,初始范围是整个中序数组
        return buildTree_func(inorder, postorder, 0, n - 1, post);
    }
};

 四、前序后序画树:

        通过利用前序遍历提供的根节点顺序和后序遍历提供的子树结构信息,通过递归方法高效构建出对应的二叉树。

  • 前序遍历 (preorder): 节点的访问顺序为根节点、左子树、右子树。

  • 后序遍历 (postorder): 节点的访问顺序为左子树、右子树、根节点。

  • 使用 unordered_map<int, int> postIndexMap 来存储后序遍历中每个节点值的索引,以便在构建树时快速查找。

  • 主函数 constructFromPrePost:

    • 首先,将后序遍历中的节点值及其索引存入哈希表 postIndexMap。这样可以在后续递归中快速查找某个节点在后序遍历中的位置。

    • 初始化前序遍历的索引 preIndex 为 0,表示从前序遍历的第一个元素开始处理。

    • 调用辅助函数 constructTree 开始构建树,初始的范围是整个后序遍历。

  • 递归函数 constructTree:

    • 基线条件:

      • 如果前序遍历的索引超出范围(preIndex >= preorder.size())或者左边界大于右边界(left > right),返回 nullptr,表示当前子树为空。

    • 创建当前根节点 root,并从前序遍历中获取其值,同时更新 preIndex 指针。

    • 如果当前子树只有一个节点(left == right),直接返回该根节点。

    • 使用 postIndexMap 找到当前根节点的左子节点在后序遍历中的索引,存储在 leftChildIndex 中。

    • 递归构建左子树和右子树:

      • 左子树的范围是 [left, leftChildIndex]

      • 右子树的范围是 [leftChildIndex + 1, right - 1](右子树的右边界需要减去1,因为当前根节点已经处理过)。

    • 返回当前构建的根节点。

class Solution {
    // 用于存储后序遍历中每个节点值的索引
    unordered_map<int, int> postIndexMap;

public:
    // 递归构建二叉树的辅助函数
    TreeNode* constructTree(vector<int>& preorder, int& preIndex, int left, int right) {
        // 基线条件:如果前序遍历的索引超出范围或左边界大于右边界,返回 nullptr
        if (preIndex >= preorder.size() || left > right) return nullptr;

        // 创建当前根节点,并更新前序遍历索引
        TreeNode* root = new TreeNode(preorder[preIndex++]);
        
        // 如果当前子树只有一个节点,直接返回根节点
        if (left == right) return root;

        // 在后序遍历中找到左子节点的索引
        int leftChildIndex = postIndexMap[preorder[preIndex]];

        // 递归构建左子树
        root->left = constructTree(preorder, preIndex, left, leftChildIndex);
        
        // 递归构建右子树,右子树的范围是左子节点的下一个位置到当前范围的最后一个节点
        root->right = constructTree(preorder, preIndex, leftChildIndex + 1, right - 1);
        
        // 返回构建的根节点
        return root;
    }

    // 主函数,从前序和后序遍历构建二叉树
    TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
        int n = postorder.size();
        
        // 将后序遍历中的节点值及其索引存入哈希表
        for (int i = 0; i < n; ++i) {
            postIndexMap[postorder[i]] = i;
        }
        
        // 初始化前序遍历的索引
        int preIndex = 0;

        // 调用辅助函数,开始构建树,初始范围是整个后序数组
        return constructTree(preorder, preIndex, 0, n - 1);
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值