分治法丨二叉树的前序遍历

分治法在二叉树遍历中是一种深度优先遍历(DFS),将问题拆解成子问题后,然后合并子问题。

  1. 分解:拆解为规模更小的子问题,将问题拆解为足够小时,然后求解。
  2. 合并:将每个子问题结果进行合并,然后完成整体问题。
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        // 结束条件
        if(root==null){
            ArrayList<Integer> res = new ArrayList<Integer>();
            return res;
        }

        // 递归拆分问题,获取子问题。
        List<Integer> leftres = preorderTraversal(root.left);
        List<Integer> rightres = preorderTraversal(root.right);

        // 合并子问题
        List<Integer> result = new ArrayList<>();
        result.add(root.val);
        result.addAll(leftres);
        result.addAll(rightres);

        // 返回合并结果
        return result;
    }
}

image-20210529082515003

第一步:拆分左右子树。

// 拆分问题,获取子问题。
List<Integer> leftres = preorderTraversal(root.left);	// 将左子树递归
List<Integer> rightres = preorderTraversal(root.right);	// 将右子树递归

第二步:合并子问题,递归到无法递归时,则会返回到叶子节点的递归调用出继续执行,开始合并结果。

// 合并子问题
List<Integer> result = new ArrayList<>();	// 创建列表存储节点信息
result.add(root.val);	// 前序遍历,先访问子树的根节点,再合并左右子树
result.addAll(leftres);	// 合并该节点的左子树的值,如果是叶子结点,左右为空,会合并一个空列表。
result.addAll(rightres);// 合并右子树的值

// 返回合并结果
return result;			// 返回本次递归的所合并的列表
  1. 在本例子中,第一个合并是先合并4号节点,因为是叶子节点,所以在该节点递归时会将叶子的节点的左右子树进行递归,因为是空节点所以会触发递归结束条件,所以叶子节点的两次左右子树的递归回返回两个空列表。

  2. 在对叶子节点进行合并子问题时,因为是前序遍历,叶子节点也可以视为一个左右孩子为空的二叉树,所以会先存储节点值,然后合并叶子节点递归调用时返回的两个空列表,然后本次递归结束并返回结果集,结果集中只有一个叶子节点的值。

  3. 上次是在2号节点递归左子树时递归到的4号节点,所以继续在2号节点继续递归右子树,5号节点仍然是个叶子节点,因此从5号递归调用时也会返回一个只含有5号节点值的列表。

  4. 2号节点的左右子树递归都执行完毕,程序继续执行,接下来则是在2号节点处合并子问题。因为前序遍历规则,所以先将2号节点值存入列表,然后把2号节点左子树的结果集合并到2号节点列表中,再把右子树的结果集合并2号节点的结果集中。所以在2号节点结果集中的顺序就是[2,4,5],合并顺序就是前序遍历规则的顺序。然后返回2号节点的结果集[2,4,5]

  5. 上次是在1号节点递归左子树时递归到的2号节点,所以继续在1号节点继续递归右子树,1号节点也是整棵二叉树的根节点,所以递归右子树顺序和左子树顺序一样,就不在赘述右子树递归顺序。2节点返回的结果集后,我们这里认为3号节点结果集也已返回。因此接下来执行合并子问题,根据前序规则,先存入1号节点的值,然后将2号节点的返回的结果集合并到1号节点的结果集中得到[1,2,4,5],然后再把3号节点结果并入结果集中得到[1,2,4,5,3,6,7],合并操作结束后,返回1号节点的结果集,至此二叉树递归完毕。

总结:先递归寻找最左叶子节点,叶子节点也是一颗特殊的二叉树,每个节点把自己的左右子树结果合并,然后将结果返回给上层调用,上层继续合并,直到返回到根节点,根节点将左右子树的结果合并后返回整颗二叉树的遍历的结果。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值