第六章 二叉树part01 理论基础 递归遍历 迭代遍历 统一迭代

第十四天| 第六章 二叉树part01 理论基础 递归遍历 迭代遍历 统一迭代

一、二叉树理论基础

1.1 结构

二叉树是这么一种树状结构:每个节点最多有两个孩子,左孩子和右孩子

重要的二叉树结构

  • 完全二叉树(complete binary tree)是一种二叉树结构,除最后一层以外,每一层都必须填满,填充时要遵从先左后右
  • 平衡二叉树(balance binary tree)是一种二叉树结构,其中每个节点的左右子树高度相差不超过 1

1.2 存储

存储方式分为两种

  • (1)定义树节点与左、右孩子引用(TreeNode)
public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(int val) {
        this.val = val;
    }

    public TreeNode(TreeNode left, int val, TreeNode right) {
        this.left = left;
        this.val = val;
        this.right = right;
    }

    public String toString() {
        return String.valueOf(this.val);
    }
}
  • (2)使用数组,前面讲堆时用过,若以 0 作为树的根,索引可以通过如下方式计算

    • 父 = floor((子 - 1) / 2)

    • 左孩子 = 父 * 2 + 1

    • 右孩子 = 父 * 2 + 2

1.3 遍历

遍历也分为两种

  1. 广度优先遍历(Breadth-first order):尽可能先访问距离根最近的节点,也称为层序遍历
  2. 深度优先遍历(Depth-first order):对于二叉树,可以进一步分成三种(要深入到叶子节点)
    1. pre-order 前序遍历,对于每一棵子树,先访问该节点,然后是左子树,最后是右子树
    2. in-order 中序遍历,对于每一棵子树,先访问左子树,然后是该节点,最后是右子树
    3. post-order 后序遍历,对于每一棵子树,先访问左子树,然后是右子树,最后是该节点
1.3.1 广度优先遍历

如果使用数组存储二叉树,按照数组索引的顺序遍历即为广度优先遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cNc7B0hA-1692716841647)(E:.STU\【JAVA】\LeetCode\第14天\二叉树广度优先遍历.png)]

1.3.2 深度优先遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P65i8LUV-1692716841648)(E:.STU\【JAVA】\LeetCode\第14天\二叉树深度优先遍历.png)]

前序遍历:中左右

中序遍历:左中右

后序遍历:左右中

下面给出二叉树的深度优先遍历的递归实现

二、递归遍历

在开始之前明确两个问题:

  • 问题一:什么时候适合使用递归呢?

    • 计算机科学中,递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集

    • 自己调用自己,如果说每个函数对应着一种解决方案,自己调用自己意味着解决方案是一样的(有规律的)

  • 问题二:我一直没搞清楚,递归中满足终止条件return后,为什么还会向上调用,从两个角度解释一下这个问题:

    • 第一,从递归的概念上看,内层函数调用(子集处理)完成,外层函数才能算调用完成

      • 深入到最里层叫做
      • 从最里层出来叫做
      • 的过程中,外层函数内的局部变量(以及方法参数)并未消失,的时候还可以用到
    • 第二,方法的调用底层使用的数据结构是****,每次调用就是一次压栈,当一个方法执行到不满足条件或者执行结束后就会弹栈,所以这就是为什么return之后仍会调用上层函数,简单来说:上层函数还在栈中。

  • 递归三部曲

    • 在二叉树这一章处理问题时刻要把握的思想:

      • (1)确定递归函数的参数和返回值;

      • (2)确定终止条件;

      • (3)确定单层递归的逻辑。

  • LeetCode给出的二叉树定义:

// 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;
    }
}

2.1 前序遍历(144. 二叉树的前序遍历)

  • 题目链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/

  • 代码:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        preorder(root, result);
        return result;
    }

    public void preorder(TreeNode root, List<Integer> result) {
        if (root == null) {
            return;
        }
        result.add(root.val);
        preorder(root.left, result);
        preorder(root.right, result);
    }
}

2.2 中序遍历(94. 二叉树的中序遍历)

  • 题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/

  • 代码:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        inorder(root, result);
        return result;
    }
    public void inorder(TreeNode root, List<Integer> result) {
        if (root == null) {
            return;
        }
        inorder(root.left, result);
        result.add(root.val);
        inorder(root.right, result);
    }
}

2.3 后序遍历(145. 二叉树的后序遍历)

  • 题目链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/

  • 代码:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        postorder(root, result);
        return result;
    }

    public void postorder(TreeNode root, List<Integer> result) {
        if (root == null) {
            return;
        }
        postorder(root.left, result);
        postorder(root.right, result);
        result.add(root.val);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值