Swift通过前序遍历和中序遍历实现重构二叉树

Swift重构二叉树

剑指Offer题目如下:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

前序遍历 遍历顺序是:A->B->C
在这里插入图片描述
中序遍历 遍历顺序是 :B->A->C

前序代码:

traverse(node : TreeNode)
{if node == null{
return null
}
访问该节点 按照该例子就是把node.val加进前序数组
traverse(node.left)
traverse(node.right)
}
}

中序代码:

traverse(node : TreeNode)
{if node == null{
return null
}

traverse(node.left)
访问该节点 按照该例子就是把node.val加进中序数组
traverse(node.right)
}
}

综上可以知道,如果给出的是前序遍历数组,他会先遍历每个小二叉树顶点,一直到最左边,所以用来分割成左右子树需要用前序遍历的每个节点;如果给出的是中序遍历数组,你可以利用前序遍历中得到的节点,找到他在中序遍历的位置,就可以把中序遍历数组分成左右两个子树数组了。我们使用递归方法,一步步把数组才分成左右子树分到不同的树节点。

下面是swift实现代码

import Foundation

public class TreeNode {
    public var left : TreeNode?
    public var right : TreeNode?
    public var val : Int = 0
    public func initWithValue(_ value : Int) {
        self.val = value
        self.left = nil
        self.right = nil
    }
}

class Solution {
    func RecreateBinaryTree(by pre : [Int] , by mid : [Int] ) -> TreeNode? {
        
        return buildTree(pre: pre, preStart: 0 , preEnd: pre.count - 1 , mid: mid, inStart: 0, inEnd: mid.count - 1)
        
    }
    
    func buildTree(pre : [Int] , preStart : Int, preEnd : Int  , mid : [Int] , inStart : Int , inEnd : Int) -> TreeNode? {
        
        if preStart > preEnd {
            return nil
        }
        
        let value = pre[preStart]
        
        let node = TreeNode()
        
        node.initWithValue(value)
        
        var index = inStart
        
        while mid[index] != value {
            index += 1
        }
        
        node.left = buildTree(pre: pre, preStart: preStart + 1, preEnd:preStart + inStart - index, mid: mid, inStart: inStart, inEnd: index-1)
        
        node.right =  buildTree(pre: pre, preStart:preStart + inStart - index + 1 , preEnd: preEnd, mid: mid, inStart: index + 1, inEnd: inEnd)
        
        return node
        
    }
}

来看看这句
node.left = buildTree(pre: pre, preStart: preStart + 1, preEnd:preStart + inStart - index, mid: mid, inStart: inStart, inEnd: index-1)
这个函数里面的参数首先由pre的数组以及其开始位置和结束位置和mid的数组以及其开始位置和结束位置构成 。pre数组就是用来提供根节点的,所以preStart+1传进去就行,但是知道根节点后,我们怎么知道pre数组几位到几位是给left的呢,这时候就要看mid数组了,我们需要用index去找到终点嘛,这个index偏移了多少位才找到中间节点,而这个多少位就是用来说明有多少个属于左子树的,我们就可以使用inStart - index来得出左子树的个数,再加上preStart就可以知道哪段范围在pre数组是属于左子树的。
node.right就跟上面思路一样。

通过二叉树前序遍历序遍历结果求后序遍历结果,可利用前序遍历序遍历的特点,结合递归的方法来实现前序遍历的顺序是先访问根节点,然后递归遍历左子树,最后递归遍历右子树;中序遍历的顺序是先递归遍历左子树,然后访问根节点,最后递归遍历右子树。因此,前序遍历的第一个元素就是二叉树的根节点,在中序遍历中找到该根节点的位置,其左边的元素就是左子树的中序遍历结果,右边的元素就是右子树的中序遍历结果。根据左子树右子树的节点数量,又可以从前序遍历中划分出左子树右子树的前序遍历结果。然后对左子树右子树分别递归地进行上述操作,直到子树为空。 以下是实现该功能的 Java 代码示例: ```java class Solution { public void postOrder(int[] pre, int[] mid, int preStart, int preEnd, int midStart, int midEnd) { if (preStart > preEnd || midStart > midEnd) { return; } // 前序遍历的第一个元素是根节点 int rootVal = pre[preStart]; // 在中序遍历中找到根节点的位置 int rootIndexInMid = midStart; while (mid[rootIndexInMid] != rootVal) { rootIndexInMid++; } // 计算左子树的节点数量 int leftSubtreeSize = rootIndexInMid - midStart; // 递归遍历左子树 postOrder(pre, mid, preStart + 1, preStart + leftSubtreeSize, midStart, rootIndexInMid - 1); // 递归遍历右子树 postOrder(pre, mid, preStart + leftSubtreeSize + 1, preEnd, rootIndexInMid + 1, midEnd); // 输出根节点 System.out.print(rootVal + " "); } public static void main(String[] args) { Solution solution = new Solution(); int[] pre = {1, 2, 4, 5, 3, 6, 7}; int[] mid = {4, 2, 5, 1, 6, 3, 7}; solution.postOrder(pre, mid, 0, pre.length - 1, 0, mid.length - 1); } } ``` 上述代码中,`postOrder` 方法接收前序遍历数组 `pre`、中序遍历数组 `mid`,以及前序遍历序遍历的起始结束索引。在方法内部,首先找到根节点,然后在中序遍历中确定根节点的位置,计算左子树的节点数量,接着递归地对左子树右子树进行处理,最后输出根节点的值,从而实现序遍历的结果输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值