二叉树----12.从前序与中序遍历序列构造二叉树

题目链接

/**

            已知:

                先序遍历(根 左 右) 与 中序遍历(左 根 右)的顺序 构建二叉树

            解法:

                1.由先序遍历确定根节点(数组第一个元素)  创建节点实例

                2.在中序遍历的数组中找到根节点,根节点两侧的元素即为二叉树的左子树与右子树

                3.被分割的子数组 两侧第一个元素即为子树的根节点 重复上述流程即可

            由遍历序列构建二叉树的通解:

                                    中序序列必备 先序,后序序列任意

                                    由先序(第一个)或后序(最后一个)确定根节点

                                    再从中序序列中定位根节点 两侧即为左右子树的节点

                                    重复上述流程 递归构建即可

*/

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    private int[] preorder;
    private int[] inorder;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        /**
            已知:
                先序遍历(根 左 右) 与 中序遍历(左 根 右)的顺序 构建二叉树
            解法: 
                1.由先序遍历确定根节点(数组第一个元素)  创建节点实例
                2.在中序遍历的数组中找到根节点,根节点两侧的元素即为二叉树的左子树与右子树
                3.被分割的子数组 两侧第一个元素即为子树的根节点 重复上述流程即可
            由遍历序列构建二叉树的通解:
                                    中序序列必备 先序,后序序列任意
                                    由先序(第一个)或后序(最后一个)确定根节点
                                    再从中序序列中定位根节点 两侧即为左右子树的节点
                                    重复上述流程 递归构建即可
        */
        this.preorder = preorder;
        this.inorder = inorder;
        return buildTree(0, preorder.length - 1, 0, inorder.length - 1);
    }


    private TreeNode buildTree(int preStart, int preEnd, int inStart, int inEnd) {
        if(preStart > preEnd || inStart > inEnd) { //任意一个数组为空 都代表构建完毕
            return null; 
        }

        //先序数组的第一个元素 即为根节点
        TreeNode root = new TreeNode(preorder[preStart]);

        //找到根节点在中序数组中的位置 区分左子树与右子树
        int index = -1;
        for(int i = inStart; i <= inEnd; i++) {
            if(inorder[i] == preorder[preStart]) {
                index = i;
                break;
            }
        }

        //计算左子树的节点个数
        //用于重新划定左 右子树 的先序数组
        int count = index - inStart;

        //递归构建左子树与右子树
        root.left = buildTree(preStart + 1, preStart + count, inStart, index - 1);
        root.right = buildTree(preStart + 1 + count, preEnd, index + 1, inEnd);

        return root;
    }
}

根据前序遍历和中序遍历序列构造二叉树的方法基于这两种遍历的特性。前序遍历的顺是根节点 -> 左子树 -> 右子树,所以前序遍历序列的第一个元素就是根节点;中序遍历的顺是左子树 -> 根节点 -> 右子树,所以可以根据根节点在中序遍历序列中的位置,将中序遍历序列划分为左子树和右子树两部分。 以下是Python实现的代码: ```python # 定义二叉树节点类 class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def buildTree(preorder, inorder): if not preorder or not inorder: return None # 前序遍历的第一个元素是根节点 root_val = preorder[0] root = TreeNode(root_val) # 在中序遍历中找到根节点的位置 inorder_index = inorder.index(root_val) # 递归构建左子树 root.left = buildTree(preorder[1:inorder_index + 1], inorder[:inorder_index]) # 递归构建右子树 root.right = buildTree(preorder[inorder_index + 1:], inorder[inorder_index + 1:]) return root # 测试代码 preorder = [1, 2, 4, 5, 3] inorder = [4, 2, 5, 1, 3] root = buildTree(preorder, inorder) ``` 以下是C++实现的代码: ```cpp #include <iostream> #include <vector> using namespace std; // 定义二叉树节点结构 struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { if (preorder.empty() || inorder.empty()) return nullptr; int root_val = preorder[0]; TreeNode* root = new TreeNode(root_val); int inorder_index = 0; while (inorder[inorder_index] != root_val) { inorder_index++; } vector<int> left_preorder(preorder.begin() + 1, preorder.begin() + inorder_index + 1); vector<int> left_inorder(inorder.begin(), inorder.begin() + inorder_index); root->left = buildTree(left_preorder, left_inorder); vector<int> right_preorder(preorder.begin() + inorder_index + 1, preorder.end()); vector<int> right_inorder(inorder.begin() + inorder_index + 1, inorder.end()); root->right = buildTree(right_preorder, right_inorder); return root; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值