1. 二叉树基础概念与Java实现
二叉树是每个节点最多有两个子节点的树形数据结构,在Java中通常通过节点类(Node class)来实现。我们先来看最基础的二叉树节点定义:
java复制class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
这个简单的类定义包含了二叉树节点的三个核心要素:存储的值(val)、左子节点指针(left)和右子节点指针(right)。在实际工程中,我们通常会把这个类定义为静态内部类,或者单独放在一个文件中。
注意:在面试中经常会被要求手写这个基础结构,务必记住val和左右指针的命名规范。有些面试官会特别关注你是否把left/right写成lChild/rChild之类的变体。
1.1 二叉树的五种基本形态
二叉树有以下五种基本形态,理解这些形态对后续算法实现至关重要:
- 空树:没有任何节点的二叉树
- 只有根节点:没有子节点的单节点树
- 只有左子树:根节点+左子树,右子树为空
- 只有右子树:根节点+右子树,左子树为空
- 完全二叉树:左右子树都存在
在Java中,我们通过null引用来表示空子树。比如要创建一个只有根节点值为5的二叉树:
java复制TreeNode root = new TreeNode(5); // left和right自动初始化为null
1.2 二叉树的性质与计算
二叉树有几个重要性质经常在面试中被考察:
- 第i层最多有2^(i-1)个节点
- 深度为k的二叉树最多有2^k - 1个节点
- 对于任何非空二叉树,如果叶子节点数为n0,度为2的节点数为n2,则n0 = n2 + 1
这些性质在解决二叉树相关算法题时非常有用。例如要计算完全二叉树的节点数:
java复制public int countNodes(TreeNode root) {
if(root == null) return 0;
return 1 + countNodes(root.left) + countNodes(root.right);
}
这个递归方法的时间复杂度是O(n),因为每个节点都会被访问一次。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二叉树的遍历方式
二叉树的遍历是面试最高频考点,必须熟练掌握四种遍历方式及其实现。
2.1 前序遍历(Preorder Traversal)
遍历顺序:根节点 → 左子树 → 右子树
递归实现:
java复制public void preorder(TreeNode root) {
if(root == null) return;
System.out.print(root.val + " "); // 先访问根节点
preorder(root.left);
preorder(root.right);
}
迭代实现(使用栈):
java复制public void preorderIterative(TreeNode root) {
if(root == null) return;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.print(node.val + " ");
// 注意右子节点先入栈
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
}
2.2 中序遍历(Inorder Traversal)
遍历顺序:左子树 → 根节点 → 右子树
递归实现:
java复制public void inorder(TreeNode root) {
if(root == null) return;
inorder(root.left);
System.out.print(root.val + " "); // 中间访问根节点
inorder(root.right);
}
迭代实现:
java复制public void inorderIterative(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
while(curr != null || !stack.isEmpty()) {
while(curr != null) {
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
System.out.print(curr.val + " ");
curr = curr.right;
}
}
面试技巧:中序遍历的迭代版本是面试中最常考的代码之一,务必能够白板写出。关键点是理解内层while循环把所有左节点压栈的过程。
2.3 后序遍历(Postorder Traversal)
遍历顺序:左子树 → 右子树 → 根节点
递归实现:
java复制public void postorder(TreeNode root) {
if(root == null) return;
postorder(root.left);
postorder(root.right);
System.out.print(root.val + " "); // 最后访问根节点
}
迭代实现(使用两个栈):
java复制public void postorderIterative(TreeNode root) {
if(root == null) return;
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(root);
while(!stack1.isEmpty()) {
TreeNode node = stack1.pop();
stack2.push(node);
if(node.left != null) stack1.push(node.left);
if(node.right != null) stack1.push(node.right);
}
while(!stack2.isEmpty()) {
System.out.print(stack2.pop().val + " ");
}
}
2.4 层序遍历(Level Order Traversal)
层序遍历使用队列实现,按层次从上到下访问节点:
java复制public void levelOrder(TreeNode root) {
if(root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int levelSize = queue.size();
for(int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
System.out.print(node.val + " ");
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
System.out.println(); // 换行表示新的一层
}
}
层序遍历在解决二叉树宽度、深度等问题时非常有用,也是许多其他算法的基础。
3. 二叉树的常见操作
3.1 插入节点
二叉树插入需要遵循一定的规则,这里以二叉搜索树为例:
java复制public TreeNode insert(TreeNode root, int val) {
if(root == null) return new TreeNode(val);
if(val < root.val) {
root.left = insert(root.left, val);
} else {
root.right = insert(root.right, val);
}
return root;
}
对于普通二叉树,通常需要指定插入位置,比如插入到第一个有空子节点的位置:
java复制public void insert(TreeNode root, int val) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if(node.left == null) {
node.left = new TreeNode(val);
return;
} else {
queue.offer(node.left);
}
if(node.right == null) {
node.right = new TreeNode(val);
return;
} else {
queue.offer(node.right);
}
}
}
3.2 删除节点
删除节点是二叉树操作中最复杂的之一,特别是对于二叉搜索树:
java复制public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return null;
if(key < root.val) {
root.left = deleteNode(root.left, key);
} else if(key > root.val) {
root.right = deleteNode(root.right, key);
} else {
// 节点只有一个子节点或没有子节点
if(root.left == null) return root.right;
if(root.right == null) return root.left;
// 节点有两个子节点:找到右子树的最小节点
TreeNode minNode = findMin(root.right);
root.val = minNode.val;
root.right = deleteNode(root.right, root.val);
}
return root;
}
private TreeNode findMin(TreeNode node) {
while(node.left != null) {
node = node.left;
}
return node;
}
3.3 查找节点
二叉搜索树的查找效率很高(平均O(log n)):
java复制public TreeNode search(TreeNode root, int val) {
if(root == null || root.val == val) return root;
if(val < root.val) {
return search(root.left, val);
} else {
return search(root.right, val);
}
}
对于普通二叉树,查找需要遍历整个树:
java复制public TreeNode search(TreeNode root, int val) {
if(root == null) return null;
if(root.val == val) return root;
TreeNode left = search(root.left, val);
if(left != null) return left;
return search(root.right, val);
}
4. 二叉树常见问题与解决方案
4.1 求二叉树的最大深度
递归解法:
java复制public int maxDepth(TreeNode root) {
if(root == null) return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
迭代解法(使用层序遍历):
java复制public int maxDepth(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 0;
while(!queue.isEmpty()) {
int size = queue.size();
depth++;
for(int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
}
return depth;
}
4.2 判断二叉树是否对称
递归解法:
java复制public boolean isSymmetric(TreeNode root) {
return root == null || isMirror(root.left, root.right);
}
private boolean isMirror(TreeNode left, TreeNode right) {
if(left == null && right == null) return true;
if(left == null || right == null) return false;
return left.val == right.val
&& isMirror(left.left, right.right)
&& isMirror(left.right, right.left);
}
迭代解法(使用队列):
java复制public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root.left);
queue.offer(root.right);
while(!queue.isEmpty()) {
TreeNode t1 = queue.poll();
TreeNode t2 = queue.poll();
if(t1 == null && t2 == null) continue;
if(t1 == null || t2 == null) return false;
if(t1.val != t2.val) return false;
queue.offer(t1.left);
queue.offer(t2.right);
queue.offer(t1.right);
queue.offer(t2.left);
}
return true;
}
4.3 二叉树的最近公共祖先(LCA)
递归解法:
java复制public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left != null && right != null) return root;
return left != null ? left : right;
}
对于二叉搜索树,可以利用其性质优化:
java复制public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(p.val < root.val && q.val < root.val) {
return lowestCommonAncestor(root.left, p, q);
} else if(p.val > root.val && q.val > root.val) {
return lowestCommonAncestor(root.right, p, q);
} else {
return root;
}
}
4.4 根据遍历序列重建二叉树
从前序和中序遍历序列构建二叉树:
java复制public TreeNode buildTree(int[] preorder, int[] inorder) {
Map<Integer, Integer> inMap = new HashMap<>();
for(int i = 0; i < inorder.length; i++) {
inMap.put(inorder[i], i);
}
return build(preorder, 0, preorder.length-1,
inorder, 0, inorder.length-1, inMap);
}
private TreeNode build(int[] preorder, int preStart, int preEnd,
int[] inorder, int inStart, int inEnd,
Map<Integer, Integer> inMap) {
if(preStart > preEnd || inStart > inEnd) return null;
TreeNode root = new TreeNode(preorder[preStart]);
int inRoot = inMap.get(root.val);
int numsLeft = inRoot - inStart;
root.left = build(preorder, preStart+1, preStart+numsLeft,
inorder, inStart, inRoot-1, inMap);
root.right = build(preorder, preStart+numsLeft+1, preEnd,
inorder, inRoot+1, inEnd, inMap);
return root;
}
从后序和中序遍历序列构建二叉树:
java复制public TreeNode buildTree(int[] inorder, int[] postorder) {
Map<Integer, Integer> inMap = new HashMap<>();
for(int i = 0; i < inorder.length; i++) {
inMap.put(inorder[i], i);
}
return build(inorder, 0, inorder.length-1,
postorder, 0, postorder.length-1, inMap);
}
private TreeNode build(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd,
Map<Integer, Integer> inMap) {
if(inStart > inEnd || postStart > postEnd) return null;
TreeNode root = new TreeNode(postorder[postEnd]);
int inRoot = inMap.get(root.val);
int numsLeft = inRoot - inStart;
root.left = build(inorder, inStart, inRoot-1,
postorder, postStart, postStart+numsLeft-1, inMap);
root.right = build(inorder, inRoot+1, inEnd,
postorder, postStart+numsLeft, postEnd-1, inMap);
return root;
}
5. 二叉树的高级应用与优化
5.1 线索二叉树
线索二叉树是为了加快遍历速度而设计的特殊二叉树,它利用空指针存储前驱或后继节点的信息:
java复制class ThreadedTreeNode {
int val;
ThreadedTreeNode left;
ThreadedTreeNode right;
boolean leftThread; // true表示left是线索,false表示left是子节点
boolean rightThread;
public ThreadedTreeNode(int val) {
this.val = val;
}
}
public class ThreadedBinaryTree {
private ThreadedTreeNode root;
private ThreadedTreeNode prev = null;
public void threadInorder() {
ThreadedTreeNode current = leftMost(root);
while(current != null) {
System.out.print(current.val + " ");
if(current.rightThread) {
current = current.right;
} else {
current = leftMost(current.right);
}
}
}
private ThreadedTreeNode leftMost(ThreadedTreeNode node) {
if(node == null) return null;
while(node.left != null && !node.leftThread) {
node = node.left;
}
return node;
}
public void createThreaded(ThreadedTreeNode root) {
if(root == null) return;
createThreaded(root.left);
if(root.left == null) {
root.left = prev;
root.leftThread = true;
}
if(prev != null && prev.right == null) {
prev.right = root;
prev.rightThread = true;
}
prev = root;
createThreaded(root.right);
}
}
5.2 平衡二叉树(AVL树)
AVL树是一种自平衡二叉搜索树,任何节点的两个子树的高度差不超过1:
java复制class AVLTreeNode {
int val, height;
AVLTreeNode left, right;
public AVLTreeNode(int val) {
this.val = val;
this.height = 1;
}
}
public class AVLTree {
private AVLTreeNode root;
private int height(AVLTreeNode node) {
return node == null ? 0 : node.height;
}
private int balanceFactor(AVLTreeNode node) {
return node == null ? 0 : height(node.left) - height(node.right);
}
private AVLTreeNode rightRotate(AVLTreeNode y) {
AVLTreeNode x = y.left;
AVLTreeNode T2 = x.right;
x.right = y;
y.left = T2;
y.height = 1 + Math.max(height(y.left), height(y.right));
x.height = 1 + Math.max(height(x.left), height(x.right));
return x;
}
private AVLTreeNode leftRotate(AVLTreeNode x) {
AVLTreeNode y = x.right;
AVLTreeNode T2 = y.left;
y.left = x;
x.right = T2;
x.height = 1 + Math.max(height(x.left), height(x.right));
y.height = 1 + Math.max(height(y.left), height(y.right));
return y;
}
public AVLTreeNode insert(AVLTreeNode node, int val) {
if(node == null) return new AVLTreeNode(val);
if(val < node.val) {
node.left = insert(node.left, val);
} else if(val > node.val) {
node.right = insert(node.right, val);
} else {
return node; // 不允许重复值
}
node.height = 1 + Math.max(height(node.left), height(node.right));
int balance = balanceFactor(node);
// 左左情况
if(balance > 1 && val < node.left.val) {
return rightRotate(node);
}
// 右右情况
if(balance < -1 && val > node.right.val) {
return leftRotate(node);
}
// 左右情况
if(balance > 1 && val > node.left.val) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// 右左情况
if(balance < -1 && val < node.right.val) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
return node;
}
}
5.3 红黑树简介
红黑树是另一种自平衡二叉搜索树,Java中的TreeMap和TreeSet就是基于红黑树实现的:
java复制class RBTreeNode {
int val;
RBTreeNode left, right, parent;
boolean isRed; // true表示红色,false表示黑色
public RBTreeNode(int val) {
this.val = val;
this.isRed = true; // 新节点默认为红色
}
}
public class RedBlackTree {
private RBTreeNode root;
private void rotateLeft(RBTreeNode x) {
RBTreeNode y = x.right;
x.right = y.left;
if(y.left != null) {
y.left.parent = x;
}
y.parent = x.parent;
if(x.parent == null) {
root = y;
} else if(x == x.parent.left) {
x.parent.left = y;
} else {
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
private void rotateRight(RBTreeNode y) {
RBTreeNode x = y.left;
y.left = x.right;
if(x.right != null) {
x.right.parent = y;
}
x.parent = y.parent;
if(y.parent == null) {
root = x;
} else if(y == y.parent.right) {
y.parent.right = x;
} else {
y.parent.left = x;
}
x.right = y;
y.parent = x;
}
public void insert(int val) {
RBTreeNode node = new RBTreeNode(val);
// 标准BST插入
// ...
// 插入后修复红黑树性质
fixInsert(node);
}
private void fixInsert(RBTreeNode node) {
// 修复逻辑
// ...
}
}
6. 二叉树在实际工程中的应用
6.1 数据库索引
B树和B+树是数据库索引最常用的数据结构,它们都是平衡多路搜索树的变种。以B+树为例:
java复制class BPlusTreeNode {
boolean isLeaf;
List<Integer> keys;
List<BPlusTreeNode> children;
BPlusTreeNode next; // 用于叶子节点链表
// 方法实现...
}
public class BPlusTree {
private BPlusTreeNode root;
private int degree;
public BPlusTree(int degree) {
this.degree = degree;
this.root = new BPlusTreeNode(true);
}
public void insert(int key, Object value) {
// 插入实现...
}
public Object search(int key) {
// 查找实现...
return null;
}
}
6.2 文件系统
许多文件系统使用B树或它的变种来组织目录结构。例如Ext文件系统的HTree索引:
java复制class HTreeNode {
int hash;
long blockPointer;
HTreeNode left, right;
// 方法实现...
}
public class HTreeIndex {
private HTreeNode root;
public long findBlock(String filename) {
int hash = filename.hashCode();
HTreeNode current = root;
while(current != null) {
if(hash == current.hash) {
return current.blockPointer;
} else if(hash < current.hash) {
current = current.left;
} else {
current = current.right;
}
}
return -1; // 未找到
}
}
6.3 游戏开发
在游戏开发中,二叉树常用于场景管理和碰撞检测。例如四叉树(Quadtree)用于2D空间分区:
java复制class Quadtree {
Rectangle boundary;
int capacity;
List<Point> points;
boolean divided;
Quadtree northeast, northwest, southeast, southwest;
public Quadtree(Rectangle boundary, int capacity) {
this.boundary = boundary;
this.capacity = capacity;
this.points = new ArrayList<>();
this.divided = false;
}
public void insert(Point point) {
if(!boundary.contains(point)) return;
if(points.size() < capacity) {
points.add(point);
} else {
if(!divided) {
subdivide();
}
northeast.insert(point);
northwest.insert(point);
southeast.insert(point);
southwest.insert(point);
}
}
private void subdivide() {
// 划分实现...
}
}
6.4 编译器设计
在编译器设计中,抽象语法树(AST)是源代码语法结构的树形表示:
java复制interface ASTNode {
void accept(Visitor visitor);
}
class BinaryExpr implements ASTNode {
ASTNode left;
Token operator;
ASTNode right;
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Visitor {
public void visit(BinaryExpr node) {
node.left.accept(this);
node.right.accept(this);
// 处理二元表达式...
}
}
7. 二叉树算法优化技巧
7.1 记忆化搜索
对于存在重复子问题的二叉树问题,可以使用记忆化技术优化:
java复制Map<TreeNode, Integer> memo = new HashMap<>();
public int maxDepthWithMemo(TreeNode root) {
if(root == null) return 0;
if(memo.containsKey(root)) return memo.get(root);
int depth = 1 + Math.max(maxDepthWithMemo(root.left),
maxDepthWithMemo(root.right));
memo.put(root, depth);
return depth;
}
7.2 尾递归优化
某些递归算法可以改写成尾递归形式,减少栈空间使用:
java复制public int maxDepthTailRec(TreeNode root) {
return helper(root, 0);
}
private int helper(TreeNode node, int depth) {
if(node == null) return depth;
return Math.max(helper(node.left, depth + 1),
helper(node.right, depth + 1));
}
7.3 迭代替代递归
许多递归算法可以转换为迭代实现,避免栈溢出风险:
java复制public List<Integer> inorderTraversalIterative(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
while(curr != null || !stack.isEmpty()) {
while(curr != null) {
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
res.add(curr.val);
curr = curr.right;
}
return res;
}
7.4 并行处理
对于大型二叉树,可以考虑并行处理子树:
java复制public int parallelCountNodes(TreeNode root) {
if(root == null) return 0;
Future<Integer> leftFuture = forkJoinPool.submit(() -> parallelCountNodes(root.left));
Future<Integer> rightFuture = forkJoinPool.submit(() -> parallelCountNodes(root.right));
try {
return 1 + leftFuture.get() + rightFuture.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
8. 二叉树常见面试题解析
8.1 验证二叉搜索树
错误解法(只检查当前节点):
java复制// 这是错误的!
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
if(root.left != null && root.left.val >= root.val) return false;
if(root.right != null && root.right.val <= root.val) return false;
return isValidBST(root.left) && isValidBST(root.right);
}
正确解法(传递上下界):
java复制public boolean isValidBST(TreeNode root) {
return isValid(root, null, null);
}
private boolean isValid(TreeNode node, Integer lower, Integer upper) {
if(node == null) return true;
if(lower != null && node.val <= lower) return false;
if(upper != null && node.val >= upper) return false;
return isValid(node.left, lower, node.val)
&& isValid(node.right, node.val, upper);
}
8.2 二叉树的直径
二叉树的直径是指任意两个节点间最长路径的长度:
java复制int maxDiameter = 0;
public int diameterOfBinaryTree(TreeNode root) {
maxDepthForDiameter(root);
return maxDiameter;
}
private int maxDepthForDiameter(TreeNode root) {
if(root == null) return 0;
int left = maxDepthForDiameter(root.left);
int right = maxDepthForDiameter(root.right);
maxDiameter = Math.max(maxDiameter, left + right);
return 1 + Math.max(left, right);
}
8.3 二叉树的最大路径和
java复制int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
private int maxGain(TreeNode node) {
if(node == null) return 0;
int leftGain = Math.max(maxGain(node.left), 0);
int rightGain = Math.max(maxGain(node.right), 0);
int priceNewpath = node.val + leftGain + rightGain;
maxSum = Math.max(maxSum, priceNewpath);
return node.val + Math.max(leftGain, rightGain);
}
8.4 二叉树的右视图
java复制public List<Integer> rightSideView(TreeNode root) {
List<Integer> result = new ArrayList<>();
if(root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int levelSize = queue.size();
for(int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
if(i == levelSize - 1) {
result.add(node.val);
}
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
}
return result;
}
9. 二叉树的学习资源与进阶路径
9.1 推荐书籍
- 《算法导论》 - 最权威的算法教材,包含二叉树相关证明和算法
- 《数据结构与算法分析:Java语言描述》 - 针对Java开发者的数据结构书籍
- 《剑指Offer》 - 包含大量二叉树面试题及解析
- 《编程珠玑》 - 包含二叉树在实际问题中的应用案例
9.2 在线学习资源
- LeetCode二叉树专题 - 包含200+二叉树相关问题
- VisuAlgo可视化工具 - 直观展示二叉树各种操作过程
- GeeksforGeeks数据结构板块 - 详细的二叉树教程和实现
- MIT OpenCourseWare算法课程 - 免费的高质量算法课程
9.3 学习路线建议
-
基础阶段:
- 掌握二叉树基本概念和性质
- 熟练实现四种遍历方式
- 理解递归在二叉树中的应用
-
进阶阶段:
- 学习各种平衡二叉树实现
- 掌握二叉树常见算法问题
- 理解二叉树在实际系统中的应用
-
高级阶段:
- 研究B树/B+树在数据库中的实现
- 学习并行二叉树算法
- 探索二叉树在机器学习中的应用
9.4 常见面试考察点
-
基础概念:
- 二叉树的性质和特点
- 各种遍历方式的特点和应用场景
- 递归与迭代的实现转换
-
算法能力:
- 路径相关问题(和、直径等)
- 子树、祖先相关问题
- 构建、转换二叉树
-
系统设计:
- 如何设计一个高效的二叉树索引
- 大规模二叉树数据的存储和处理
- 二叉树在分布式系统中的应用
10. 二叉树实战:实现一个简单的二叉搜索树
最后,我们实现一个完整的二叉搜索树(BST)类,包含基本操作:
java复制public class BinarySearchTree {
private TreeNode root;
public void insert(int val) {
root = insertRec(root, val);
}
private TreeNode insertRec(TreeNode root, int val) {
if(root == null) return new TreeNode(val);
if(val < root.val) {
root.left = insertRec(root.left, val);
} else if(val > root.val) {
root.right = insertRec(root.right, val);
}
return root;
}
public boolean search(int val) {
return searchRec(root, val) != null;
}
private TreeNode searchRec(TreeNode root, int val) {
if(root == null || root.val == val) return root;
return val < root.val ? searchRec(root.left, val)
: searchRec(root.right, val);
}
public void delete(int val) {
root = deleteRec(root, val);
}
private TreeNode deleteRec(TreeNode root, int val) {
if(root == null) return null;
if(val < root.val) {
root.left = deleteRec(root.left, val);
} else if(val > root.val) {
root.right = deleteRec(root.right, val);
} else {
if(root.left == null) return root.right;
if(root.right == null) return root.left;
TreeNode minNode = findMin(root.right);
root.val = minNode.val;
root.right = deleteRec(root.right, root.val);
}
return root;
}
private TreeNode findMin(TreeNode node) {
while(node.left != null) {
node = node.left;
}
return node;
}
public List<Integer> inorder() {
List<Integer> result = new ArrayList<>();
inorderRec(root, result);
return result;
}
private void inorderRec(TreeNode root, List<Integer> result) {
if(root == null) return;
inorderRec(root.left, result);
result.add(root.val);
inorderRec(root.right, result);
}
// 其他方法...
}
这个BST实现包含了插入、查找、删除和中序遍历等基本操作。在实际应用中,可能需要添加更多功能,如范围查询、批量操作等。
