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

相关文章:

  • Linux 如何统计系统上各个用户登录(或者登出)记录出现的次数?
  • Android-三种持久化方式详解
  • 摘录-打造第二大脑
  • J2EE模式---表现层集成模式
  • C++ TAP(基于任务的异步编程模式)
  • Web后端进阶:springboot原理(面试多问)
  • React入门学习——指北指南(第五节)
  • JavaScript手录06-函数
  • 【RK3568 PWM 子系统(SG90)驱动开发详解】
  • 数据赋能(336)——技术平台——智能化运营
  • Java动态调试技术原理
  • 【RocketMQ】一分钟了解RocketMQ
  • 告别复杂配置!Spring Boot优雅集成百度OCR的终极方案
  • Windows 平台源码部署 Dify教程(不依赖 Docker)
  • 《C++ list 完全指南:从基础到高效使用》
  • Linux——线程同步
  • InvokeRepeating避免嵌套调用
  • C++编程学习(第16天)
  • 7月26日京东秋招第一场第一题
  • 【第二章-数据的表示和运算】
  • 基于java的在线教育平台管理系统、在线学习系统的设计与实现
  • 【机器学习-2】 | 决策树算法基础/信息熵
  • 背包问题及 LIS 优化
  • 【Ubuntu】发展历程
  • 排序算法,咕咕咕
  • 疏老师-python训练营-Day26函数专题1:函数定义与参数
  • Linux的生态与软件安装
  • 深入浅出学习 KNN 算法:从原理到数字识别实践
  • Matrix Theory study notes[5]
  • 7月26日京东秋招第一场第二题