二叉树的基本操作
二叉树的类由节点的值,节点的左枝,节点的友枝
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;
}
}
方法说明:
- size() - 递归计算节点总数
- getLeafNodeCount() - 计算叶子节点(没有子节点的节点)数量
- getKLevelNodeCount() - 计算指定层数的节点数量
- getHeight() - 计算树的高度(深度)
- find() - 查找指定值的节点
- levelOrder() - 层序遍历(广度优先遍历)
- 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));
}
}