二叉搜索树
又叫二叉查找树,BST树
定义
左子树所有节点的值小于根节点,右子树所有节点的值大于根节点(左 < 根 < 右),且左右子树也是这样。
特点
-
支持高效查找(类似二分查找)(因为当遍历到一个节点的时候,先判断目标值同节点值的大小,然后确定进行左子节点的遍历还是右子节点的遍历,相当于少遍历了一半的数据 ),所以时间复杂度度==O (logn)==
-
从左到右遍历(中序遍历)可得到一个有序的序列。
-
==BST通常不允许重复的值==

缺点:
当依次插入的数据都比上一个数据值大时,所有的节点就会依次堆到右子节点,此时树就成了一个链表的结构了,查询时间复杂度就降为了==O(n)==

代码实现:
java
package com.stu.shujujiegou;
/**
* @title:
* @auther: eleven
* @description:
* @data: 2025/8/5 16:45
* @parm:
* @return:
*/
import java.util.ArrayList;
import java.util.List;
public class BinarySearchTree {
// 二叉搜索树节点类
private static class TreeNode {
int val;
TreeNode left; // 左子节点
TreeNode right; // 右子节点
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
private TreeNode root; // 根节点
// 构造空树
public BinarySearchTree() {
root = null;
}
/**
* 插入元素
* @param val 要插入的值
*/
public void insert(int val) {
root = insertRecursive(root, val);
}
// 递归插入
private TreeNode insertRecursive(TreeNode current, int val) {
// 如果当前节点为空,创建新节点作为插入位置
if (current == null) {
return new TreeNode(val);
}
// 根据值的大小决定插入左子树还是右子树
if (val < current.val) {
current.left = insertRecursive(current.left, val);
} else if (val > current.val) {
current.right = insertRecursive(current.right, val);
}
// 相等的值不插入(BST通常不允许重复值)
return current;
}
/**
* 查找元素
* @param val 要查找的值
* @return 找到返回true,否则返回false
*/
public boolean contains(int val) {
return containsRecursive(root, val);
}
// 递归查找
private boolean containsRecursive(TreeNode current, int val) {
// 节点为空,未找到
if (current == null) {
return false;
}
// 找到匹配的值
if (val == current.val) {
return true;
}
// 小于当前节点值,去左子树查找;否则去右子树查找
return val < current.val
? containsRecursive(current.left, val)
: containsRecursive(current.right, val);
}
/**
* 删除元素
* @param val 要删除的值
* @return 删除成功返回true,否则返回false
*/
public boolean delete(int val) {
// 如果树为空,直接返回false
if (root == null) {
return false;
}
// 记录删除前是否包含该值
boolean exists = contains(val);
if (exists) {
root = deleteRecursive(root, val);
}
return exists;
}
// 递归删除
private TreeNode deleteRecursive(TreeNode current, int val) {
if (current == null) {
return null;
}
// 1. 查找要删除的节点
if (val < current.val) {
current.left = deleteRecursive(current.left, val);
} else if (val > current.val) {
current.right = deleteRecursive(current.right, val);
} else {
// 2. 找到要删除的节点,处理三种情况
// 情况1:叶子节点(没有子节点)
if (current.left == null && current.right == null) {
return null;
}
// 情况2:只有一个子节点
if (current.left == null) {
return current.right; // 返回右子节点
}
if (current.right == null) {
return current.left; // 返回左子节点
}
// 情况3:有两个子节点
// 因为二叉搜索树 数据有序满足 左<中<右,所以我们删除当前节点后,需要找到右子树的最小节点替换到当前位置
// 找到右子树中的最小值节点
TreeNode smallestNode = findSmallest(current.right);
// 用最小值替换当前节点值
current.val = smallestNode.val;
// 删除右子树中的最小值节点
current.right = deleteRecursive(current.right, smallestNode.val);
}
return current;
}
// 查找最小节点(最左节点)
private TreeNode findSmallest(TreeNode node) {
return node.left == null ? node : findSmallest(node.left);
}
// 查找最大节点(最右节点)
private TreeNode findLargest(TreeNode node) {
return node.right == null ? node : findLargest(node.right);
}
/**
* 获取最小值
* @return 树中的最小值
*/
public int findMin() {
if (root == null) {
throw new IllegalStateException("树为空,无法查找最小值");
}
return findSmallest(root).val;
}
/**
* 获取最大值
* @return 树中的最大值
*/
public int findMax() {
if (root == null) {
throw new IllegalStateException("树为空,无法查找最大值");
}
return findLargest(root).val;
}
/**
* 前序遍历(根 -> 左 -> 右)
* @return 遍历结果列表
*/
public List<Integer> preOrder() {
List<Integer> result = new ArrayList<>();
preOrderRecursive(root, result);
return result;
}
private void preOrderRecursive(TreeNode node, List<Integer> result) {
if (node != null) {
result.add(node.val); // 访问根节点
preOrderRecursive(node.left, result); // 遍历左子树
preOrderRecursive(node.right, result); // 遍历右子树
}
}
/**
* 中序遍历(左 -> 根 -> 右)
* 对于BST,中序遍历结果是升序的
* @return 遍历结果列表
*/
public List<Integer> inOrder() {
List<Integer> result = new ArrayList<>();
inOrderRecursive(root, result);
return result;
}
private void inOrderRecursive(TreeNode node, List<Integer> result) {
if (node != null) {
inOrderRecursive(node.left, result); // 遍历左子树
result.add(node.val); // 访问根节点
inOrderRecursive(node.right, result); // 遍历右子树
}
}
/**
* 后序遍历(左 -> 右 -> 根)
* @return 遍历结果列表
*/
public List<Integer> postOrder() {
List<Integer> result = new ArrayList<>();
postOrderRecursive(root, result);
return result;
}
private void postOrderRecursive(TreeNode node, List<Integer> result) {
if (node != null) {
postOrderRecursive(node.left, result); // 遍历左子树
postOrderRecursive(node.right, result); // 遍历右子树
result.add(node.val); // 访问根节点
}
}
/**
* 层序遍历(按层次从上到下,从左到右)
* @return 遍历结果列表
*/
public List<Integer> levelOrder() {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
// 使用队列实现层序遍历
java.util.Queue<TreeNode> queue = new java.util.LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
result.add(node.val);
// 左子节点入队
if (node.left != null) {
queue.add(node.left);
}
// 右子节点入队
if (node.right != null) {
queue.add(node.right);
}
}
return result;
}
/**
* 清空树
*/
public void clear() {
root = null;
}
/**
* 检查树是否为空
* @return 空返回true,否则返回false
*/
public boolean isEmpty() {
return root == null;
}
// 测试方法
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
// 插入元素
bst.insert(50);
bst.insert(30);
bst.insert(70);
bst.insert(20);
bst.insert(40);
bst.insert(60);
bst.insert(80);
System.out.println("中序遍历(升序): " + bst.inOrder());
// 输出: [20, 30, 40, 50, 60, 70, 80]
System.out.println("前序遍历: " + bst.preOrder());
// 输出: [50, 30, 20, 40, 70, 60, 80]
System.out.println("后序遍历: " + bst.postOrder());
// 输出: [20, 40, 30, 60, 80, 70, 50]
System.out.println("层序遍历: " + bst.levelOrder());
// 输出: [50, 30, 70, 20, 40, 60, 80]
System.out.println("最小值: " + bst.findMin()); // 输出: 20
System.out.println("最大值: " + bst.findMax()); // 输出: 80
System.out.println("是否包含60: " + bst.contains(60)); // 输出: true
System.out.println("是否包含90: " + bst.contains(90)); // 输出: false
// 删除元素
bst.delete(30);
System.out.println("删除30后的中序遍历: " + bst.inOrder());
// 输出: [20, 40, 50, 60, 70, 80]
bst.delete(50);
System.out.println("删除50后的中序遍历: " + bst.inOrder());
// 输出: [20, 40, 60, 70, 80]
}
}
重点看数据插入和数据删除
数据插入:
java
/**
* 插入元素
* @param val 要插入的值
*/
public void insert(int val) {
root = insertRecursive(root, val);
}
// 递归插入
private TreeNode insertRecursive(TreeNode current, int val) {
// 如果当前节点为空,创建新节点作为插入位置
if (current == null) {
return new TreeNode(val);
}
// 根据值的大小决定插入到左子树还是右子树
if (val < current.val) {
current.left = insertRecursive(current.left, val);
} else if (val > current.val) {
current.right = insertRecursive(current.right, val);
}
// 相等的值不插入(BST通常不允许重复值)
return current;
}
数据删除:
java
/**
* 删除元素
* @param val 要删除的值
* @return 删除成功返回true,否则返回false
*/
public boolean delete(int val) {
// 如果树为空,直接返回false
if (root == null) {
return false;
}
// 记录删除前是否包含该值
boolean exists = contains(val);
if (exists) {
root = deleteRecursive(root, val);
}
return exists;
}
// 递归删除
private TreeNode deleteRecursive(TreeNode current, int val) {
if (current == null) {
return null;
}
// 1. 查找要删除的节点
if (val < current.val) {
current.left = deleteRecursive(current.left, val);
} else if (val > current.val) {
current.right = deleteRecursive(current.right, val);
} else {
// 2. 找到要删除的节点,处理三种情况
// 情况1:叶子节点(没有子节点)
if (current.left == null && current.right == null) {
return null;
}
// 情况2:只有一个子节点
if (current.left == null) {
return current.right; // 返回右子节点
}
if (current.right == null) {
return current.left; // 返回左子节点
}
// 情况3:有两个子节点
// 因为二叉搜索树 数据有序且满足 左<中<右,所以我们删除当前节点后,需要找到右子树的最小节点替换到当前位置
// 找到右子树中的最小值节点
TreeNode smallestNode = findSmallest(current.right);
// 用最小值替换当前节点值
current.val = smallestNode.val;
// 删除右子树中的最小值节点
current.right = deleteRecursive(current.right, smallestNode.val);
}
return current;
}
对应代码中==情况2==,只有一个子节点:

对应代码中==情况3==:被删除节点有两个子节点:
