当前位置: 首页 > 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.xdnf.cn/news/1188595.html

相关文章:

  • 【RK3568 PWM 子系统(SG90)驱动开发详解】
  • 记录和分享抓取的数字货币和大A时序数据
  • k8s:将打包好的 Kubernetes 集群镜像推送到Harbor私有镜像仓库
  • 容器化成本优化:K8s资源请求与限制的黄金法则——从资源画像分析到25%成本削减的实战指南
  • python面向对象编程详解
  • k8s之控制器详解
  • Go语言unsafe包深度解析
  • Go 多模块仓库标签管理教程
  • 嵌入式硬件篇---zigbee无线串口通信问题解决方法
  • Android 修改系统时间源码阅读
  • Linux的生态与软件安装
  • 主要分布在腹侧海马体(vHPC)CA1区域(vCA1)的混合调谐细胞(mixed-tuning cells)对NLP中的深层语义分析的积极影响和启示
  • 车载诊断刷写 --- Flash关于擦除和写入大小
  • 【MySQL】深入浅出事务:保证数据一致性的核心武器
  • 深度解析 noisereduce:开源音频降噪库实践
  • 【影刀RPA_初级课程_我的第一个机器人】
  • LeetCode|Day26|191. 位 1 的个数|Python刷题笔记
  • 像素、视野、光源,都有哪些因素影响测量精度?
  • DSP在CCS中实现双核在线仿真调试及下载的方法(以TMS320F28x为例)
  • 【Redis】 Redis 基础命令和原理
  • 详解力扣高频SQL50题之1193. 每月交易 I【简单】
  • MySQL操作进阶
  • 1. 多线程开发
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 热词评论查询功能实现
  • 机器学习(重学版)基础篇(概念与评估)
  • Qt 远程过程调用(RPC)实现方案
  • 大模型应用班-第2课 DeepSeek使用与提示词工程课程重点 学习ollama 安装 用deepseek-r1:1.5b 分析PDF 内容
  • UniappDay03
  • 高斯数据库触发器实现流水号的
  • 去中心化时代的通信革命:briefing与cpolar技术融合带来的安全范式革新