二叉树基础
二叉树是数据结构中非常重要的一种非线性结构,它以层次化的方式存储数据,在查找、排序等场景中有着广泛应用。本文将结合具体代码实现,详细介绍二叉树的基本概念、操作及相关知识点。
一、二叉树的基本概念
二叉树是由 n(n≥0)个节点组成的有限集合,每个节点最多有两个子节点,分别称为左子节点和右子节点。特殊的二叉树包括:
- 空二叉树:节点数为 0 的二叉树
- 满二叉树:所有叶子节点都在同一层,且非叶子节点都有两个子节点
- 完全二叉树:除最后一层外,其他层的节点数都达到最大值,且最后一层的节点都靠左排列
二、二叉搜索树(BST)的实现
我们实现的BinaryTree
类本质上是一棵二叉搜索树,它具有以下特性:左子树的所有节点值小于根节点值,右子树的所有节点值大于等于根节点值。
1. 节点类(Node)
节点是二叉树的基本组成单元,包含节点值和左右子节点的引用:
java
package 二叉树;
public class Node {
public int value;
public Node left; // 左子节点
public Node right; // 右子节点
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value=" + value + ", left=" + left + ", right=" + right + "]";
}
}
2. 二叉树核心操作
(1)插入操作
插入操作是构建二叉搜索树的基础,根据二叉搜索树的特性,新节点会被放置在正确的位置:
java
// 插入节点
public void insert(int num) {
Node node = new Node(num);
if(root == null) { // 树为空时,新节点作为根节点
root = node;
return;
}
Node index = root;
while(true) {
if(index.value > num) { // 小于当前节点,向左子树查找
if(index.left == null) {
index.left = node;
return;
}
index = index.left;
} else { // 大于等于当前节点,向右子树查找
if(index.right == null) {
index.right = node;
return;
}
index = index.right;
}
}
}
(2)遍历操作
遍历是二叉树最常用的操作,主要有深度优先遍历和广度优先遍历两大类:
- 先序遍历:根节点 → 左子树 → 右子树
java
public void beforeOrder(Node node) {
if(node == null) return;
System.out.println(node.value); // 访问根节点
beforeOrder(node.left); // 遍历左子树
beforeOrder(node.right); // 遍历右子树
}
- 中序遍历:左子树 → 根节点 → 右子树(对二叉搜索树进行中序遍历可得到有序序列)
java
public void inOrder(Node node) {
if(node == null) return;
inOrder(node.left); // 遍历左子树
System.out.println(node.value); // 访问根节点
inOrder(node.right); // 遍历右子树
}
- 后序遍历:左子树 → 右子树 → 根节点
java
public void afterOrder(Node node) {
if(node == null) return;
afterOrder(node.left); // 遍历左子树
afterOrder(node.right); // 遍历右子树
System.out.println(node.value); // 访问根节点
}
- 广度优先遍历(层序遍历):按层次依次访问各节点,使用队列实现
java
public void levelOrder() {
Queue<Node> queue = new LinkedList<Node>();
queue.add(root);
while(!queue.isEmpty()) {
Node index = queue.poll();
System.out.println(index.value); // 访问当前节点
if(index.left != null) {
queue.add(index.left); // 左子节点入队
}
if(index.right != null) {
queue.add(index.right); // 右子节点入队
}
}
}
三、代码测试与运行
Test
类用于验证二叉树的功能:
java
public class Test {
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
// 插入节点构建二叉树
tree.insert(5);
tree.insert(10);
tree.insert(3);
tree.insert(1);
tree.insert(4);
tree.insert(11);
tree.insert(8);
System.out.println("树的结构:");
System.out.println(tree); // 打印树的结构
System.out.println("层序遍历结果:");
tree.levelOrder(); // 执行层序遍历
}
}
四、二叉树重要知识点
-
二叉树的高度与深度
- 节点的深度:从根节点到该节点的路径长度
- 节点的高度:从该节点到最深叶子节点的路径长度
- 树的高度:根节点的高度
-
二叉搜索树的时间复杂度
- 插入、查找、删除操作的平均时间复杂度为 O (log n)
- 在最坏情况下(树退化为链表),时间复杂度为 O (n)
-
平衡二叉树
- 为解决二叉搜索树在最坏情况下的性能问题,出现了平衡二叉树(如 AVL 树、红黑树)
- 平衡二叉树通过旋转操作维持树的平衡性,保证操作的时间复杂度稳定在 O (log n)
-
二叉树的应用场景
- 数据库索引(B 树、B + 树)
- 表达式解析(表达式树)
- Huffman 编码(用于数据压缩)
- 决策树(机器学习领域)
-
删除操作要点
- 删除叶子节点:直接删除
- 删除只有一个子节点的节点:用子节点替代被删除节点
- 删除有两个子节点的节点:找到中序后继(右子树中最小节点)或中序前驱(左子树中最大节点)替代,再删除该后继 / 前驱节点