轻松掌握数据结构:二叉树

二叉树

二叉树是非线性数据结构的一种,由节点组成,非空二叉树包含一个根节点和左右子树,左右子树也都是二叉树。

名词解释:

  • 节点:包含数据元素及指向子节点的引用(指针);
  • 根节点:二叉树的起始节点,无父节点;
  • 叶子节点:无左、右子节点的节点(度为 0);
  • 节点的度:节点拥有的子节点数量(0、1 或 2);
  • 树的深度(高度):从根节点到最深叶子节点的路径长度(根节点深度为 1,空树深度为 0);
  • 节点的层次:根节点为第 1 层,其子节点为第 2 层,以此类推;
  • 祖先 / 后代:从根节点到某节点的路径上的所有节点为该节点的祖先;某节点的所有子树节点为其后代。

代码实现二叉树

java 复制代码
public class BinaryTree<T> {
    // 二叉树节点类
    public static class TreeNode<T> {
        T data;                // 节点数据
        TreeNode<T> left;      // 左子节点
        TreeNode<T> right;     // 右子节点

        public TreeNode(T data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }

        public TreeNode(T data, TreeNode<T> left, TreeNode<T> right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }
    }

    protected TreeNode<T> root;  // 根节点

    // 构造空树
    public BinaryTree() {
        root = null;
    }

    // 根据根节点构造树
    public BinaryTree(TreeNode<T> root) {
        this.root = root;
    }

    // 判断树是否为空
    public boolean isEmpty() {
        return root == null;
    }

    // 获取树的高度
    public int height() {
        return height(root);
    }

    // 递归计算树的高度
    private int height(TreeNode<T> node) {
        if (node == null) {
            return 0;
        }
        // 树的高度 = 1 + 左子树高度和右子树高度的最大值
        int leftHeight = height(node.left);
        int rightHeight = height(node.right);
        return Math.max(leftHeight, rightHeight) + 1;
    }

    // 获取树的节点数
    public int size() {
        return size(root);
    }

    // 递归计算节点数
    private int size(TreeNode<T> node) {
        if (node == null) {
            return 0;
        }
        // 总节点数 = 1(当前节点) + 左子树节点数 + 右子树节点数
        return 1 + size(node.left) + size(node.right);
    }

    // 前序遍历(根 -> 左 -> 右)
    public void preOrder() {
        preOrder(root);
        System.out.println();
    }

    private void preOrder(TreeNode<T> node) {
        if (node != null) {
            System.out.print(node.data + " ");  // 访问根节点
            preOrder(node.left);                // 遍历左子树
            preOrder(node.right);               // 遍历右子树
        }
    }

    // 中序遍历(左 -> 根 -> 右)
    public void inOrder() {
        inOrder(root);
        System.out.println();
    }

    private void inOrder(TreeNode<T> node) {
        if (node != null) {
            inOrder(node.left);                 // 遍历左子树
            System.out.print(node.data + " ");  // 访问根节点
            inOrder(node.right);                // 遍历右子树
        }
    }

    // 后序遍历(左 -> 右 -> 根)
    public void postOrder() {
        postOrder(root);
        System.out.println();
    }

    private void postOrder(TreeNode<T> node) {
        if (node != null) {
            postOrder(node.left);               // 遍历左子树
            postOrder(node.right);              // 遍历右子树
            System.out.print(node.data + " ");  // 访问根节点
        }
    }

    // 层序遍历(按层次从上到下,从左到右)
    public void levelOrder() {
        if (root == null) {
            return;
        }

        // 使用队列实现层序遍历
        java.util.Queue<TreeNode<T>> queue = new java.util.LinkedList<>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            TreeNode<T> node = queue.poll();
            System.out.print(node.data + " ");

            // 左子节点入队
            if (node.left != null) {
                queue.offer(node.left);
            }
            // 右子节点入队
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        System.out.println();
    }

    // 测试方法
    public static void main(String[] args) {
        // 构建一棵示例二叉树:
        //       1
        //      / \
        //     2   3
        //    / \   \
        //   4   5   6
        TreeNode<Integer> node4 = new TreeNode<>(4);
        TreeNode<Integer> node5 = new TreeNode<>(5);
        TreeNode<Integer> node6 = new TreeNode<>(6);
        TreeNode<Integer> node2 = new TreeNode<>(2, node4, node5);
        TreeNode<Integer> node3 = new TreeNode<>(3, null, node6);
        TreeNode<Integer> node1 = new TreeNode<>(1, node2, node3);

        BinaryTree<Integer> tree = new BinaryTree<>(node1);

        System.out.println("树的高度:" + tree.height());  // 输出:3
        System.out.println("树的节点数:" + tree.size());  // 输出:6

        System.out.print("前序遍历:");
        tree.preOrder();  // 输出:1 2 4 5 3 6

        System.out.print("中序遍历:");
        tree.inOrder();   // 输出:4 2 5 1 3 6

        System.out.print("后序遍历:");
        tree.postOrder(); // 输出:4 5 2 6 3 1

        System.out.print("层序遍历:");
        tree.levelOrder();// 输出:1 2 3 4 5 6
    }
}

重要特点

  1. 第i层最多节点数:第i层((i > 1))最多有==2^(i-1)==个节点。

    例:第 1 层最多 1 个(根节点),第 2 层最多 2 个,第 3 层最多 4 个,以此类推。

  2. 深度为k的二叉树最多节点数:总节点数==最多为2^k - 1==(满二叉树的情况)。

    例:深度为 3 的满二叉树最多有(2^3 - 1 = 7)个节点。

  3. 节点数与度的关系:若叶子节点数为(n_0),度为 2 的节点数为(n_2),则(n_0 = n_2 + 1)。 推导:总节点数(n = n_0 + n_1 + n_2)((n_1)为度为 1 的节点数),总边数(n-1 = n_1 + 2n_2),联立得(n_0 = n_2 + 1)。

完全二叉树

假设一个二叉树由h层,那么如果从1 ~~ h-1 层的节点数都达到了最大的个数,并且第h层的节点是从左往右依次分布的,中间没有空缺,就是完全二叉树。


![image-20250806114336827](二叉树.assets/image-20250806114336827.png)

以下这个就不是一个完全二叉树

因为倒数第二层,没有达到节点数的最大值

满二叉树

满二叉树是指树的所有层的节点数都达到了最大值

相关推荐
该用户已不存在4 分钟前
OpenJDK、Temurin、GraalVM...到底该装哪个?
java·后端
怀刃24 分钟前
内存监控对应解决方案
后端
西工程小巴30 分钟前
实践笔记-VSCode与IDE同步问题解决指南;程序总是进入中断服务程序。
c语言·算法·嵌入式
码事漫谈39 分钟前
VS Code Copilot 内联聊天与提示词技巧指南
后端
Tina学编程41 分钟前
48Days-Day19 | ISBN号,kotori和迷宫,矩阵最长递增路径
java·算法
Moonbit1 小时前
MoonBit Perals Vol.06: MoonBit 与 LLVM 共舞 (上):编译前端实现
后端·算法·编程语言
Moonbit1 小时前
MoonBit Perals Vol.06: MoonBit 与 LLVM 共舞(下):llvm IR 代码生成
后端·程序员·代码规范
Moonbit1 小时前
MoonBit Pearls Vol.05: 函数式里的依赖注入:Reader Monad
后端·rust·编程语言
小奋斗1 小时前
深入浅出:ES5/ES6+数组扁平化详解
javascript·面试
bobz9651 小时前
ThanosRuler
后端