当前位置: 首页 > news >正文

二叉搜索树(Binary Search Tree)详解与java实现

定义

二叉搜索树(BST)是一种特殊的二叉树,它具有以下特性:

  1. 左子树上所有节点的值均小于它的根节点的值
  2. 右子树上所有节点的值均大于它的根节点的值
  3. 左右子树也分别为二叉搜索树(递归定义)

这种特性使得二叉搜索树的查找、插入和删除操作都能高效进行,平均时间复杂度为 O (log n)。

java实现

import java.util.LinkedList;
import java.util.Queue;// 二叉搜索树实现
public class BinarySearchTree {// 节点类private static class Node {int val;Node left;Node right;Node(int val) {this.val = val;left = null;right = null;}}private Node root; // 根节点// 构造函数public BinarySearchTree() {root = null;}// 插入节点public void insert(int val) {root = insertRec(root, val);}// 递归插入private Node insertRec(Node root, int val) {// 如果树为空,创建新节点作为根节点if (root == null) {root = new Node(val);return root;}// 否则递归向下查找插入位置if (val < root.val) {root.left = insertRec(root.left, val);} else if (val > root.val) {root.right = insertRec(root.right, val);}// 值相等的情况,通常不插入(BST一般不允许重复值)return root;}// 查找节点public boolean search(int val) {return searchRec(root, val);}// 递归查找private boolean searchRec(Node root, int val) {// 树为空或未找到if (root == null) {return false;}// 找到目标值if (root.val == val) {return true;}// 递归查找左子树或右子树return val < root.val ? searchRec(root.left, val) : searchRec(root.right, val);}// 删除节点public void delete(int val) {root = deleteRec(root, val);}// 递归删除private Node deleteRec(Node root, int val) {// 树为空if (root == null) {return root;}// 查找要删除的节点if (val < root.val) {root.left = deleteRec(root.left, val);} else if (val > root.val) {root.right = deleteRec(root.right, val);} else {// 找到要删除的节点// 情况1:叶子节点或只有一个子节点if (root.left == null) {return root.right;} else if (root.right == null) {return root.left;}// 情况2:有两个子节点// 找到中序后继(右子树的最小值)root.val = minValue(root.right);// 删除中序后继root.right = deleteRec(root.right, root.val);}return root;}// 查找最小值(最左节点)private int minValue(Node root) {int minVal = root.val;while (root.left != null) {root = root.left;minVal = root.val;}return minVal;}// 查找最大值(最右节点)public int maxValue() {if (root == null) {throw new IllegalStateException("树为空");}Node current = root;while (current.right != null) {current = current.right;}return current.val;}// 中序遍历(升序输出)public void inorder() {inorderRec(root);System.out.println();}private void inorderRec(Node root) {if (root != null) {inorderRec(root.left);System.out.print(root.val + " ");inorderRec(root.right);}}// 前序遍历public void preorder() {preorderRec(root);System.out.println();}private void preorderRec(Node root) {if (root != null) {System.out.print(root.val + " ");preorderRec(root.left);preorderRec(root.right);}}// 后序遍历public void postorder() {postorderRec(root);System.out.println();}private void postorderRec(Node root) {if (root != null) {postorderRec(root.left);postorderRec(root.right);System.out.print(root.val + " ");}}// 层序遍历public void levelOrder() {if (root == null) {return;}Queue<Node> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {Node current = queue.poll();System.out.print(current.val + " ");if (current.left != null) {queue.add(current.left);}if (current.right != null) {queue.add(current.right);}}System.out.println();}// 测试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 int key = 40;System.out.println("查找 " + key + ": " + (bst.search(key) ? "找到" : "未找到")); // 找到key = 90;System.out.println("查找 " + key + ": " + (bst.search(key) ? "找到" : "未找到")); // 未找到System.out.println("最大值: " + bst.maxValue()); // 80// 删除节点bst.delete(20);System.out.println("删除20后中序遍历:");bst.inorder(); // 30 40 50 60 70 80 bst.delete(30);System.out.println("删除30后中序遍历:");bst.inorder(); // 40 50 60 70 80 bst.delete(50);System.out.println("删除50后中序遍历:");bst.inorder(); // 40 60 70 80 }
}

代码解析

  1. 节点结构

    • 每个节点包含一个值(val)、左子节点(left)和右子节点(right)
  2. 核心操作

    • 插入:从根节点开始,根据值的大小决定向左或向右子树插入
    • 查找:利用 BST 特性,通过比较值的大小快速定位节点
    • 删除:分三种情况处理
      • 叶子节点:直接删除
      • 只有一个子节点:用子节点替代当前节点
      • 有两个子节点:用右子树的最小值(中序后继)替代当前节点,再删除该最小值节点
  3. 遍历方式

    • 中序遍历:左→根→右(输出结果为升序)
    • 前序遍历:根→左→右
    • 后序遍历:左→右→根
    • 层序遍历:按层次从上到下、从左到右遍历

二叉搜索树的应用场景

  • 用于实现关联数组、映射等数据结构
  • 数据库索引
  • 高效的查找、插入和删除操作场景
  • 范围查询(如查找某个区间内的所有元素)

需要注意的是,在最坏情况下(如插入有序数据),二叉搜索树可能退化为链表,导致操作效率下降到 O (n)。为解决这个问题,出现了平衡二叉搜索树,如 AVL 树和红黑树,它们通过自平衡机制保持树的高度在 log n 级别。

http://www.dtcms.com/a/299992.html

相关文章:

  • 代码随想录打卡第十五天
  • 睡眠函数 Sleep() C语言
  • AI Agent开发学习系列 - langchain: 本地大模型调用
  • CMU15445-2024fall-project4踩坑经历
  • 设计自己的小传输协议 状态机解析与封装抽象
  • Java设计模式之行为型模式(中介者模式)实现方式详解
  • 函数参数的解包与顺序匹配机制
  • Go的管道——channel
  • HTML5元素相关补充
  • HighlightingSystem
  • MATLAB近红外光谱分析技术及实践技术应用
  • C++ 类型萃取:深入理解与实践
  • 【AcWing 143题解】最大异或对
  • Android-广播详解
  • 零拷贝应用场景
  • 【Spring AI】大模型服务平台-阿里云百炼
  • 基于cooragent的旅游多智能体的MCP组件安装与其开发
  • javaSE 6
  • connect系统调用及示例
  • Go-Elasticsearch v9 安装与版本兼容性
  • Docker常用命令详解:以Nginx为例
  • 求hom_math_2d的角度值
  • Aerospike架构深度解析:打造web级分布式应用的理想数据库
  • JS实现数字变化时,上下翻滚动画效果
  • 本地部署智能家居集成解决方案 ESPHome 并实现外部访问
  • 五分钟系列-文本搜索工具grep
  • 【工具】好用的浏览器AI助手
  • 【MySQL】VARCHAR(10) 和 VARCHAR(100) 的区别
  • 大模型蒸馏(distillation)---从DeepseekR1-1.5B到Qwen-2.5-1.5B蒸馏
  • 拒绝SQL恐惧:用Python+pyqt打造任意Excel数据库查询系统