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

先序遍历和中序遍历

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[] inorder, int inorderLeft, int inorderRight) {
        if(inorderLeft >= inorderRight){
            //中序遍历区间为空,当前子树为空树
            return null;
        }
        if(index >= preorder.length){
            //先序中的所有元素都访完毕
            return null;
        }
        //根据index取出当前树的根节点的值,并构造根节点
            TreeNode newNode = new TreeNode(preorder[index]);
        //知道根节点后,需要根据根节点,在中序遍历结果中找到左右子树的范围
            //找出当前节点在中序结果中的位置,位置确定,左右子树位置就确定了
            //左子树对应的中序区间[inorderLeft,pos)
            //右子树对应的中序区间[pos+1,inorderRight)
            int pos = find(inorder,inorderLeft,inorderRight,newNode.val);//在中序遍历中找到节点的下标
            index++;//只++一次
            newNode.left = buildTreeHelper(preorder,inorder,inorderLeft,pos);
            newNode.right = buildTreeHelper(preorder,inorder,pos+1,inorderRight);
            return newNode;
    }
    private int find(int[] inorder, int inorderLeft, int inorderRight, int val) {
        for(int i = inorderLeft;i < inorderRight; i++){
            if(inorder[i] == val){
                return i;
            }
        }
        return -1;
    }

后序遍历和中序遍历

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

在这里插入图片描述
后序遍历为9-》15-》7-》20-》3
后序遍历结果倒置3-》20-》7-》15-》9 相当于一个“镜像”先序,先根节点再右子树再左子树
所以先对后序遍历的数组逆序,之后对上述的代码进行修改先进行右子树再进行左子树即可。

在这里插入图片描述

private int index = 0;
    public TreeNode buildTree(int[] inorder, int[] posorder){
        index = 0;
        int[] posorder1 = new int[posorder.length];
        for(int i = 0; i < posorder.length; i++){
            posorder1[i] = posorder[posorder.length-i-1];
        }
        return buildTreeHelper(posorder1,inorder,0,inorder.length);
    }
    private TreeNode buildTreeHelper(int[] posorder1, int[] inorder, int inorderLeft, int inorderRight) {
        if(inorderLeft >= inorderRight){
            return null;
        }
        if(index >= posorder1.length){
            return null;
        }
        TreeNode newNode = new TreeNode(posorder1[index]);
        int pos = find(inorder,inorderLeft,inorderRight,newNode.val);
        index++;//只++一次
        newNode.right = buildTreeHelper(posorder1,inorder,pos+1,inorderRight);
        newNode.left = buildTreeHelper(posorder1,inorder,inorderLeft,pos);
        return newNode;
    }
    private int find(int[] inorder, int inorderLeft, int inorderRight, int val) {
        for(int i = inorderLeft;i < inorderRight; i++){
            if(inorder[i] == val){
                return i;
            }
        }
        return -1;
    }
在C语言中,给定一棵已知的二叉树序遍历(根节点 -> 左子树 -> 右子树)序遍历(左子树 -> 根节点 -> 右子树),我们可以通过递归的方式求得后序遍历(左子树 -> 右子树 -> 根节点)。这是因为前序、中序后序遍历之间存在一定的关联: 1. **后序遍历**的根节点在最后,所以我们可以通过以下步骤找到它: - 当遍历到当前节点时,如果它是序遍历的第一个元素,那么它就是根节点。 - 接着,我们在中序遍历中查找该节点的位置。由于中序遍历根节点位于左右子树之间,所以我们可以找到从当前开始的剩余部分,这部分就是中序遍历剩下的左子树右子树。 - 对这个剩余部分分别进行后序遍历即可得到完整的后序遍历序列。 下面是递归实现的伪代码示例: ```c struct TreeNode *findRoot(struct TreeNode *root, int preorder[], int size) { // 序遍历第一个元素即为根节点 if (preorder[0] == root->val) return root; // 中序遍历找到根节点的位置 for (int i = 1; i < size; i++) { if (preorder[i] == root->val) { return findRoot(root->left, inorder, size); } } } void postorderTraversal(struct TreeNode *root, int inorder[], int size) { if (root == NULL) return; postorderTraversal(root->left, inorder, size); postorderTraversal(root->right, inorder, size); // 将找到的根节点添加到后序序列的末尾 insertAtEnd(postorder, root->val); // 假设insertAtEnd()是一个函数用于将值追加到数组末尾 } ``` 这里假设`inorder[]`数组保存了中序遍历的结果,并且`postorder[]`数组用于存储最终的后序遍历结果。你需要根据实际情况调整这些操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值