二叉树操作全解析:从递归到层序遍历

二叉树的基本操作

二叉树的类由节点的值,节点的左枝,节点的友枝

java 复制代码
import java.util.LinkedList;
import java.util.Queue;

/**
 * 二叉树节点类
 */
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    
    TreeNode(int val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
    
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

方法说明:

  1. size() - 递归计算节点总数
  2. getLeafNodeCount() - 计算叶子节点(没有子节点的节点)数量
  3. getKLevelNodeCount() - 计算指定层数的节点数量
  4. getHeight() - 计算树的高度(深度)
  5. find() - 查找指定值的节点
  6. levelOrder() - 层序遍历(广度优先遍历)
  7. isCompleteTree() - 判断是否为完全二叉树

时间复杂度分析:

  • 所有方法的时间复杂度都是 O(n),其中 n 是节点数
  • 空间复杂度:递归方法为 O(h)(h为树高),层序遍历方法为 O(w)(w为树的最大宽度)

使用建议:

  • 对于大型二叉树,注意递归深度可能导致的栈溢出问题
  • 层序遍历使用队列,适合需要按层处理节点的场景
  • 完全二叉树的判断算法利用了层序遍历的特性

1. 获取树中节点的个数

时间复杂度:O(n),需要遍历所有节点

空间复杂度:O(h),递归栈深度为树的高度

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

2. 获取叶子节点的个数

叶子节点:没有子节点的节点

java 复制代码
public int getLeafNodeCount(TreeNode root) {
        if (root == null){
            return 0;
        }
        if (root.left == null && root.right == null){
            // 当前节点是叶子节点
            return 1;
        }
        // 递归计算左右子树的叶子节点数
        return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
}

3. 获取第K层节点的个数

java 复制代码
/**
     * @param root 根节点
     * @param k 目标层数(从1开始计数)
     */
public int getKLevelNodeCount(TreeNode root, int k) {
        if (root == null || k <= 0) {
            return 0;
        }
        if (k == 1) {
            // 第1层只有根节点
            return 1;
        }
        // 第k层节点数 = 左子树的第k-1层节点数 + 右子树的第k-1层节点数
        return getKLevelNodeCount(root.left,k-1) + getKLevelNodeCount(root.right,k-1);
}

4. 获取二叉树的高度(深度)

高度:从根节点到最远叶子节点的最长路径上的节点数

java 复制代码
public int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        // 当前节点高度 = 1 + max(左子树高度, 右子树高度)
       return Math.max(getHeight(root.left),getHeight(root.right)) + 1;
}

5. 检测值为value的元素是否存在

java 复制代码
public TreeNode find(TreeNode root, int val) {
        if (root == null){
            return null;
        }
        if(root.val == val){
            return root;
        }
        // 先在左子树中查找
        TreeNode left = find(root.left,val);
        if(left != null){
            return root;
        }
        // 左子树没找到,再在右子树中查找
        return find(root.right,val);
}

6. 层序遍历(广度优先遍历)

java 复制代码
public void levelOrder(TreeNode root) {
        if(root == null){
            System.out.println("空树");
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (queue.peek() != null){
            queue.offer(queue.peek().left);
            queue.offer(queue.peek().right);
            System.out.print(queue.poll().val+" ");
        }
        System.out.println();    
}

7. 判断一棵树是不是完全二叉树

完全二叉树:除了最后一层,其他层都是满的,且最后一层的节点都靠左排列

java 复制代码
public boolean isCompleteTree(TreeNode root) {
        if (root == null) {
            return true;
        }
        
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        boolean reachedEnd = false; // 标记是否遇到了第一个空节点
        
        while (!queue.isEmpty()) {
            TreeNode current = queue.poll();
            
            if (current == null) {
                // 遇到空节点,标记为已到达末尾
                reachedEnd = true;
            } else {
                // 如果已经遇到过空节点,又遇到了非空节点,说明不是完全二叉树
                if (reachedEnd) {
                    return false;
                }
                // 将左右子节点加入队列(即使是null也要加入)
                queue.offer(current.left);
                queue.offer(current.right);
            }
        }
        
        return true;
}

测试

java 复制代码
public class Test {
    public static void main(String[] args) {
        // 构建测试二叉树
        //       1
        //      / \
        //     2   3
        //    / \   \
        //   4   5   6
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.right = new TreeNode(6);


        // 测试各个方法
        System.out.println("节点总数: " + root.size(root));
        System.out.println("叶子节点数: " + root.getLeafNodeCount(root));
        System.out.println("第2层节点数: " + root.getKLevelNodeCount(root, 2));
        System.out.println("树的高度: " + root.getHeight(root));

        TreeNode found = root.find(root, 5);
        System.out.println("查找值为5的节点: " + (found != null ? "找到,值为" + found.val : "未找到"));

        root.levelOrder(root);
        System.out.println("是否是完全二叉树: " + root.isCompleteTree(root));

        // 修改树结构使其成为完全二叉树
        root.right.left = new TreeNode(7);
        System.out.println("修改后是否是完全二叉树: " + root.isCompleteTree(root));
    }
}
相关推荐
代码什么用11 小时前
Spring基础使用
java·后端·spring
信奥卷王11 小时前
[GESP202609 六级] 分树规划
算法
Su米苏11 小时前
Spring AI 中MCP 与普通 @Tool的区别
java·人工智能·spring
夏幻灵12 小时前
LeetCode 21:合并两个有序链表——双指针与哑节点详解
算法·leetcode·链表
码云数智-园园12 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言
老板一杯拿铁12 小时前
Java 异常体系详解:从字节码原理到最佳实践
java
蜗牛互联网12 小时前
Java 17 HttpClient调用文件转写API的超时与失败回退
java·人工智能·后端
禾小西12 小时前
07丨Redis 哨兵机制:主库故障后,如何恢复服务?
java·开发语言·redis
我不是阵雨12 小时前
JDK 21虚拟线程Pinning陷阱:一文拔钉解困
java·开发语言