【Java】二叉树

二叉树

什么是二叉树?

二叉树(Binary Tree) 是每个节点最多有两个子树的树结构,通常子树被称作"左子树"和"右子树"。

首先,定义二叉树节点的Java类:

java 复制代码
public class TreeNode<T> {
    public T val;                  // 节点值
    public TreeNode<T> left;       // 左子节点
    public TreeNode<T> right;      // 右子节点
    
    public TreeNode() {}
    
    public TreeNode(T val) {
        this.val = val;
    }
    
    public TreeNode(T val, TreeNode<T> left, TreeNode<T> right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

二叉树有五种基本形态:

  1. 空二叉树
  2. 只有一个根节点
  3. 只有左子树
  4. 只有右子树
  5. 左右子树都有

二叉树的分类

满二叉树

除了叶子节点外,每个节点都有左右两个子节点,且所有叶子节点都在最底层。

完全二叉树

除最后一层外,其余各层节点数都达到最大,且最后一层的叶子节点从左到右连续排列 。Java中的PriorityQueue底层就是基于完全二叉树的数组实现。

二叉搜索树(BST)

具有以下性质:

  • 左子树上所有节点的值 < 根节点的值
  • 右子树上所有节点的值 > 根节点的值
  • 左右子树本身也是BST

平衡二叉树(AVL树)

任意节点的左右子树高度差不超过1。Java的TreeMap底层使用的红黑树就是一种自平衡二叉搜索树。

二叉树常用操作

二叉树的遍历

前序遍历(根 → 左 → 右)

java 复制代码
// 递归实现
public void preOrder(TreeNode<T> root, List<T> result) {
    if (root == null) return;
    result.add(root.val);           // 访问根
    preOrder(root.left, result);    // 遍历左子树
    preOrder(root.right, result);   // 遍历右子树
}
java 复制代码
// 迭代实现(栈)
public List<T> preOrderIterative(TreeNode<T> root) {
    List<T> result = new ArrayList<>();
    if (root == null) return result;
    
    Deque<TreeNode<T>> stack = new ArrayDeque<>();
    stack.push(root);
    
    while (!stack.isEmpty()) {
        TreeNode<T> node = stack.pop();
        result.add(node.val);
        // 先压右,再压左(栈是后进先出)
        if (node.right != null) stack.push(node.right);
        if (node.left != null) stack.push(node.left);
    }
    return result;
}

中序遍历(左 → 根 → 右)

对于二叉搜索树,中序遍历会得到一个有序序列

dart 复制代码
// 递归实现
public void inOrder(TreeNode<T> root, List<T> result) {
    if (root == null) return;
    inOrder(root.left, result);
    result.add(root.val);
    inOrder(root.right, result);
}
java 复制代码
// 迭代实现
public List<T> inOrderIterative(TreeNode<T> root) {
    List<T> result = new ArrayList<>();
    Deque<TreeNode<T>> stack = new ArrayDeque<>();
    TreeNode<T> curr = root;
    
    while (curr != null || !stack.isEmpty()) {
        // 一路向左
        while (curr != null) {
            stack.push(curr);
            curr = curr.left;
        }
        curr = stack.pop();
        result.add(curr.val);
        curr = curr.right;
    }
    return result;
}

后序遍历(左 → 右 → 根)

常用于先处理子节点再处理父节点的场景。

java 复制代码
// 递归实现
public void postOrder(TreeNode<T> root, List<T> result) {
    if (root == null) return;
    postOrder(root.left, result);
    postOrder(root.right, result);
    result.add(root.val);
}

层序遍历(BFS)

借助队列实现,常用于解决最短路径类问题。

java 复制代码
public List<List<T>> levelOrder(TreeNode<T> root) {
    List<List<T>> result = new ArrayList<>();
    if (root == null) return result;
    
    Queue<TreeNode<T>> queue = new LinkedList<>();
    queue.offer(root);
    
    while (!queue.isEmpty()) {
        int levelSize = queue.size();
        List<T> currentLevel = new ArrayList<>();
        
        for (int i = 0; i < levelSize; i++) {
            TreeNode<T> node = queue.poll();
            currentLevel.add(node.val);
            
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
        }
        result.add(currentLevel);
    }
    return result;
}

求节点总数

java 复制代码
// 1. 求节点总数
 public int countNodes(TreeNode<T> root) {
     if (root == null) return 0;
     return countNodes(root.left) + countNodes(root.right) + 1;
 }

求叶子节点个数

java 复制代码
public int countLeaves(TreeNode<T> root) {
    if (root == null) return 0;
    if (root.left == null && root.right == null) return 1;
    return countLeaves(root.left) + countLeaves(root.right);
}

求树的最大深度

java 复制代码
// 3. 求树的最大深度
public int maxDepth(TreeNode<T> root) {
    if (root == null) return 0;
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}

判断两棵树是否相同

java 复制代码
// 4. 判断两棵树是否相同
public boolean isSameTree(TreeNode<T> p, TreeNode<T> q) {
    if (p == null && q == null) return true;
    if (p == null || q == null) return false;
    if (!p.val.equals(q.val)) return false;
    return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}

判断是否是对称二叉树

java 复制代码
// 5. 判断是否是对称二叉树
public boolean isSymmetric(TreeNode<T> root) {
    if (root == null) return true;
    return isMirror(root.left, root.right);
}
private boolean isMirror(TreeNode<T> left, TreeNode<T> right) {
    if (left == null && right == null) return true;
    if (left == null || right == null) return false;
    return left.val.equals(right.val)
        && isMirror(left.left, right.right)
        && isMirror(left.right, right.left);
}

翻转二叉树(镜像)

java 复制代码
// 6. 翻转二叉树(镜像)
public TreeNode<T> invertTree(TreeNode<T> root) {
    if (root == null) return null;
    
    // 交换左右子树
    TreeNode<T> temp = root.left;
    root.left = invertTree(root.right);
    root.right = invertTree(temp);
    
    return root;
}

Java集合框架中的二叉树

Java标准库中多处使用了基于二叉树的实现:

类名 底层数据结构 特点
TreeMap 红黑树 有序键值对,O(log n)操作
TreeSet 红黑树 有序不重复集合
PriorityQueue 二叉堆(完全二叉树) 优先级队列
HashMap(JDK8+) 数组+链表+红黑树 冲突严重时链表转红黑树
相关推荐
坚持编程的菜鸟2 小时前
The Blocks Problem
数据结构·c++·算法
凌冰_2 小时前
Servlet+Thymeleaf + Fetch 实现无刷新异步请求
java·servlet
下北沢美食家2 小时前
JavaScript面试题2
开发语言·javascript·ecmascript
深蓝轨迹2 小时前
面试常见的jdk---LTS版本新特性梳理
java·面试·jdk
宵时待雨2 小时前
优选算法专题1:双指针
数据结构·c++·笔记·算法·leetcode
汀、人工智能2 小时前
[特殊字符] 第107课:LRU缓存(最后一课[特殊字符])
数据结构·算法·链表·数据库架构·哈希表·lru缓存
数据知道2 小时前
claw-code 源码分析:大型移植的测试哲学——如何用 unittest 门禁守住「诚实未完成」的口碑?
开发语言·python·ai·claude code·claw code
Stella Blog2 小时前
狂神Java基础学习笔记Day01
java·笔记·学习
李白的天不白2 小时前
java处理跨域请求
java