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

二叉树的基本操作

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

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));
    }
}
相关推荐
小的~~1 小时前
ThreadLocal 、InheritableThreadLocal 与 TransmittableThreadLocal 的进阶指南
java·开发语言
北极糊的狐1 小时前
钉钉小程序报错data.formatTime is not a function是因为 axml 模板中不能直接调用 Page 内自定义方法!
java·小程序·钉钉
.道阻且长.10 小时前
2.LeetCode算法习题讲解--双指针--复写零
算法·leetcode·职场和发展
·薯条大王10 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
To_OC12 小时前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
白狐_79812 小时前
408数据结构第5章:二叉树遍历序列题——技巧、判断与真题型总结
数据结构
ZJH__GO14 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
程序员黑豆14 小时前
Windows 系统 Java 环境变量配置全攻略:解决“不是内部或外部命令”
java·前端·ai编程