Day14~二叉树的递归遍历、迭代遍历、统一迭代

250 阅读5分钟

摘要

本文主要介绍了二叉树的理论基础,并提供了多种二叉树遍历方式,包括递归遍历、迭代遍历以及统一迭代方式。

1、理论基础

1.1 什么是二叉树

二叉树(Binary Tree)是一种树状数据结构,其中每个节点最多有两个子节点,分别是左子节点和右子节点。每个节点可以包含数据(通常是一个值)以及指向其左子节点和右子节点的指针。

二叉树有以下几个重要特性:

  1. 根节点(Root): 二叉树的顶端节点,是整个树的起始点。
  2. 节点(Node): 二叉树中的每个元素都被称为节点,每个节点可以包含一个值或数据。
  3. 父节点和子节点: 除了根节点,每个节点都有一个父节点,以及零个、一个或两个子节点。这些子节点分别是左子节点和右子节点。
  4. 叶子节点(Leaf Node): 没有子节点的节点被称为叶子节点,它们位于二叉树的末端。
  5. 深度(Depth): 从根节点到某个节点的路径的长度,表示该节点的深度。
  6. 高度(Height): 从某个节点到其最远叶子节点的路径的长度,表示以该节点为根的子树的高度。根节点的高度为整棵树的高度。

1.2 二叉树的种类

  1. 满二叉树(Full Binary Tree): 满二叉树是一种特殊的二叉树,每个节点要么没有子节点(叶子节点),要么恰好有两个子节点。这意味着所有的非叶子节点都有两个子节点,使得树的高度达到最小可能的高度。满二叉树通常用于一些数学和计算机科学的理论研究中。
  2. 完全二叉树(Complete Binary Tree): 完全二叉树是一种二叉树,除了最后一层,其它每一层都是满的,最后一层的节点从左到右填充,没有留下空缺。完全二叉树常常用于堆的实现,因为它具有很好的平衡性和性能。
  3. 二叉搜索树(Binary Search Tree,BST): 二叉搜索树是一种有序的二叉树,其中每个节点的值都大于其左子树中的所有节点的值,小于其右子树中的所有节点的值。这个性质使得BST非常适合进行快速的查找、插入和删除操作。BST的性能取决于树的平衡性,最坏情况下可能退化为链表,导致操作的时间复杂度变为O(n)。
  4. 平衡二叉搜索树(Balanced Binary Search Tree): 平衡二叉搜索树是一种特殊的BST,它的左右子树的高度差不超过1。平衡二叉搜索树的目的是确保树的高度保持较小的范围,以保证各种操作的时间复杂度都接近O(log n)。常见的平衡二叉搜索树包括AVL树和红黑树。

1.3 二叉树的存储方式

  1. 链式存储(Linked Representation): 这是最常见的方式,也是最直观的。每个二叉树节点都包含数据以及指向其左子树和右子树的指针(引用)。这种方式易于实现和理解,适用于树结构的动态操作,但它可能会占用更多的内存空间,因为每个节点都需要额外的指针。
  2. 数组存储(Array Representation): 这种方式将二叉树的节点按照某种顺序存储在数组中。通常使用广度优先遍历(层序遍历)的方式进行存储,根节点存储在索引0处,左子节点在2i+1处,右子节点在2i+2处。这种方式节省了指针的内存开销,但对于不完全二叉树,可能会浪费一些数组空间。

1.4 二叉树的定义

二叉树(Binary Tree)是一种数据结构,其中每个节点最多有两个子节点,分别是左子节点和右子节点。二叉树的定义可以使用Java代码表示如下:

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
​
    TreeNode(int val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}

在上面的代码中,TreeNode 类表示二叉树的节点。每个节点包含一个整数值 val 作为节点的数据,以及左子节点 left 和右子节点 right 的引用。初始时,这两个引用都为空,表示该节点没有左子节点和右子节点。

你可以使用这个定义创建二叉树的节点,连接它们以构建二叉树。例如,创建一个包含三个节点的简单二叉树可以如下所示:

TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);

这段代码创建了一个根节点为1,左子节点为2,右子节点为3的二叉树。

这只是二叉树的基本定义,实际上,二叉树的应用非常广泛,包括二叉搜索树、平衡二叉树、堆等。具体的二叉树类型和操作会根据应用的不同而有所不同。

2、递归遍历

2.1 前序遍历

    // 前序遍历:中左右
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        doPreorderTraversal(root, list);
        return list;
    }
​
    public void doPreorderTraversal(TreeNode root, List<Integer> list) {
        if(root == null) {
            return;
        }
​
        list.add(root.val);
        doPreorderTraversal(root.left, list);
        doPreorderTraversal(root.right, list);
    }

2.2 中序遍历

    // 中序遍历:左中右
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        doInorderTraversal(root, list);
        return list;
    }
​
    public void doInorderTraversal(TreeNode root, List<Integer> list) {
        if(root == null) {
            return;
        }
​
        doInorderTraversal(root.left, list);
        list.add(root.val);
        doInorderTraversal(root.right, list);
    }

2.3 后序遍历

    // 后序遍历:左右中
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        doPostorderTraversal(root, list);
        return list;
    }
​
    public void doPostorderTraversal(TreeNode root, List<Integer> list) {
        if(root == null) {
            return;
        }
​
        doPostorderTraversal(root.left, list);
        doPostorderTraversal(root.right, list);
        list.add(root.val);
    }

3、迭代遍历 *

4、统一迭代 *

参考资料

代码随想录-二叉树理论基础篇

代码随想录-二叉树的递归遍历

代码随想录-二叉树的迭代遍历

代码随想录-二叉树的统一迭代法