二叉搜索树【Java】

news2024/11/25 18:46:38

文章目录

    • 二叉搜索树的性质
    • 二叉搜索树的操作
      • 遍历
      • 查找
      • 插入
      • 删除

二叉搜索树又称为二叉排序树,是一种具有一定性质的特殊的二叉树;

二叉搜索树的性质

若它的左子树不为空,则左子树上结点的值均小于根节点的值;
若它的右子树不为空,则右子树上结点的值均大于根节点的值;
二叉搜索树的左右子树均为二叉搜索树;

在这里插入图片描述

二叉搜索树的操作

遍历

关于二叉树的遍历方式有前序、中序、后序三种,对于二叉搜索树而言,使用中序遍历得到的结点序列是有序的;

public class BinarySearchTree {
//首先创建相关的结点结构
    static class TreeNode {
        public int key;
        public TreeNode left;
        public TreeNode right;

        TreeNode(int key){
            this.key=key;
        }
    }

    public TreeNode root;

//进行中序遍历
	public void inorder(TreeNode root){
        if (root==null) return;
        inorder(root.left);
        System.out.println(root.key+" ");
        inorder(root.right);
    }
}

查找

基于二叉搜索树的性质,当根节点不为空时,可以根据根节点的值与待查找的值key之间的关系进行查找;即若根节点的值大于key,则在其左子树进行查找;若根节点的值小于key,则到其右子树进行查找;直到最终根节点的值为空或没有找到key则结束;

public TreeNode search(int key){
        //定义一个cur从根节点的位置开始查找
        TreeNode cur=root;
        while (cur!=null){
            //结点的值与key相等,找到并返回
            if (cur.key==key){
                return cur;
            }else if(cur.key<key){
                //结点的值小于key,去其右子树进行查找
                cur=cur.right;
            }else {
                //结点的值大于key,去其左子树进行查找
                cur=cur.left;
            }
        }

        //没有找到,没有该值
        return null;
    }

插入

插入操作可以分为2种情况:当根节点为空时,直接插入到根节点即可;当根节点不为空时,就需要遵守搜索树的性质按照之前查找的逻辑,将节点插入合适的位置,保证不破坏其二叉搜索树的结构;

 public boolean insert (int key){
        //结点为空,直接进行插入
        if (root==null){
            root=new TreeNode(key);
            return true;
        }

        //结点不为空
        //定义一个cur寻找插入的合适位置
        TreeNode cur=root;
        //记录cur的位置或走向
        TreeNode parent=null;

        //寻找合适的插入位置,使用parent记录
        while (cur!=null){
            if (cur.key<key){
                parent=cur;
                cur=cur.right;
            }else if (cur.key<key){
                parent=cur;
                cur=cur.left;
            }else{
                //不可以插入相同的数据
                return false;
            }
        }
        //创建新结点
        TreeNode node=new TreeNode(key);
        if (parent.key<key){
            parent.right=node;

        }else{
            parent.left=node;
        }
        return true;
    }

删除

删除操作相较于前面的查找插入操作要略显复杂,大致可以分为下面几种情况:

设待删除的结点为cur,待删除节点的双亲结点为parent;

  1. cur.left==null;

cur是root;

在这里插入图片描述
cur不是root,又可以分为2种情况:

cur是其双亲结点parent的左结点:

在这里插入图片描述
cur是其双亲结点parent的右结点:

在这里插入图片描述

  1. cur.right==null;

cur为root;

在这里插入图片描述

cur不是root,又可以分为2种情况:

cur是其双亲结点parent的左结点:

在这里插入图片描述
cur是其双亲结点parent的右结点:

在这里插入图片描述

  1. cur.left!=null && cur.right!=null;

使用替换法进行删除,使用待删除节点的右子树的最小值将待删除节点进行替换,再删除最小值的结点即可;

在这里插入图片描述

下面是具体的代码实现:

public boolean remove(int key){
        TreeNode cur=root;
        TreeNode parent=null;
        //寻找删除的结点的位置
        while (cur!=null){
            if (cur.key<key){
                parent=cur;
                cur=cur.right;

            }else if(cur.key==key){
                //调用removeNode方法进行具体的删除
                removeNode(parent,cur);
                return true;
            }else{
                parent=cur;
                cur=cur.left;
            }

            }
        return false;
        }

    private void removeNode(TreeNode parent, TreeNode cur) {
        //第一种情况
        if (cur.left==null){
            if (cur==root){
                root=cur.right;
            }else if(cur==parent.left){
                parent.left=cur.right;
            }else {
                parent.right=cur.right;
            }
            //第二种情况
        }else if(cur.right==null){
            if (cur==root){
                root=cur.left;
            }else if(cur==parent.left){
                parent.left=cur.left;
            }else {
                parent.right=cur.left;
            }
        }else{
            //第三种情况,使用替换法
            TreeNode targetParent=cur;
            TreeNode target=cur.right;
            //寻找最小值
            while (target.left!=null){
                targetParent=target;
                target=target.left;
            }
            //进行替换
            cur.key=target.key;
            //删除那个最小值
            if (target==targetParent.left){
                targetParent.left=target.right;
            }else{
                targetParent.right=target.right;
            }
        }
    }

对于这样一棵二叉搜索树而言,一般情况下结点所处的位置越深,需要进行比较的次数就越多。因此根据结点插入的次序不同,就可能得到不同结构的二叉树:

最好情况下,得到一棵完全二叉树的结构,平均比较次数达到logN(以2为底);
最坏情况下,得到一棵单分支树,平均比较次数为N/2;

over!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/475974.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

08 Kubernetes应用配置管理

课件 在 Kubernetes 中&#xff0c;secret 是一种用于存储敏感信息的对象。Kubernetes 支持以下三种类型的 secret&#xff1a; Opaque&#xff1a;这是默认的 secret 类型&#xff0c;可以用于存储任何类型的数据&#xff0c;包括字符串、二进制数据等。 Service Account&…

【P2】Jmeter 线程组的并行与串行

一、串行与并行规则 &#xff08;1&#xff09;、测试计划中的执行顺序遵循&#xff1a;setUp 线程组 -> 线程组 -> tearDown 线程组 &#xff08;2&#xff09;、如果将测试计划中的独立运行每个线程组勾选上&#xff0c;则多个线程组串行执行&#xff0c;否则并发执行…

吴恩达 Chatgpt prompt 工程--5.Transforming

探索如何将大型语言模型用于文本转换任务&#xff0c;如语言翻译、拼写和语法检查、音调调整和格式转换。 Setup import openai import osfrom dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv()) # read local .env fileopenai.api_key os.getenv(OPE…

2.6 浮点运算方法和浮点运算器

学习目标&#xff1a; 以下是一些具体的学习目标&#xff1a; 理解浮点数的基本概念和表示方法&#xff0c;包括符号位、指数和尾数。学习浮点数的运算规则和舍入规则&#xff0c;包括加、减、乘、除、开方等。了解浮点数的常见问题和误差&#xff0c;例如舍入误差、溢出、下…

Unity一般打包流程

Unity一般打包流程 通常打包流程主要是通过 Building setting来选择需要打包的场景后出包到指定文件夹位置&#xff0c;也可以采用 [MenuItem("MyMenu/Do Something")]中使用static函数来选择打包路径和打包方式——需要将该脚本放置在 Editor文件夹下 [MenuItem(&…

Vue3源码 第六篇-JavaScript AST transform函数

系列文章目录 Vue3源码 第一篇-总览 Vue3源码 第二篇-Reactive API Vue3源码 第三篇-Vue3是如何实现响应性 Vue3源码 第四篇-Vue3 setup Vue3源码 第五篇-Vue3 模版compile AST生成篇 文章目录 系列文章目录前言一、transform 转换二、traverseNode 遍历节点&#xff0c;trave…

B/S结构系统的会话机制(session)

B/S结构系统的会话机制(session) 文章目录 B/S结构系统的会话机制(session)每博一文案1. session 会话机制的概述2. 什么是 session 的会话3. session 的作用4. session 的实现原理解释5. 补充&#xff1a; Cookie禁用了&#xff0c;session还能找到吗 &#xff1f;6. 总结一下…

PCA学习

前置知识 统计 假设数据集 X ∈ R n m \mathbf{X}\in\mathbb{R}^{n\times m} X∈Rnm,其中 n n n表示样本数量&#xff0c; m m m表示特征个数 均值 X ˉ 1 n e T X 1 n ∑ i 1 n X i \bar{\mathbf{X}} \frac{1}{n}\mathbf{e}^T\mathbf{X} \frac{1}{n} \sum_{i1}^{n}\mat…

[架构之路-178]-《软考-系统分析师》- 分区操作系统(Partition Operating System)概述

目录&#xff1a; 本文概述&#xff1a; 1.1 什么是分区操作系统 1.2 分区操作系统出现背景 1. 前后台系统(Foreground/Background System) 2. 实时操作系统(RTOS) 本文概述&#xff1a; 随着嵌入式系统日趋复杂化以及对安全性要求的不断提高&#xff0c;采用空间隔离、时…

java学习之枚举二

目录 一、enum关键字实现枚举 二、注意事项 一、对Season2进行反编译&#xff08;javap&#xff09; ​编辑 三、练习题 第一题 第二题 一、enum关键字实现枚举 package enum_;public class Enumeration03 {public static void main(String[] args) {System.out.println…

el-upload组件的文件回显功能和添加文件到elupload组件

省流&#xff1a; 先获取这个文件对象&#xff0c;使用handleStart方法添加到组件。 this.$refs.uploadRefName.handleStart(rawfile); 在开发的时候遇到表单里需要上传图片的功能。看了下el-upload组件的使用方法&#xff0c;在修改表单的时候&#xff0c;el-upload组件的回显…

flutter学习之旅(二)

如果不知道怎么安装编写可以查看这篇 创建项目 另一个创建方法 flutter create 项目名热部署 vscode 热部署 vscode很简单&#xff1a;可以通过Debug进行调试 使用flutter查看设备 flutter devices如图所见我现在用的是windows所以&#xff0c;我们检测不到ios因为 我们看…

【Fluent】边界类型总结,什么时候用壁面对(wall-shadow pair)、什么时候用interface?

一、fluent自动生成边界类型的规律 Enclosure是包裹在外面的气体&#xff08;流体&#xff09;&#xff0c;mold是模具&#xff08;固体&#xff09;&#xff0c;sheet是模具上的薄板件&#xff08;固体&#xff09;。 1.1 正向思维 不管是流体域还是固体域&#xff0c;每一…

高度可定制可用于商用目的全流程供应链系统(全部源码)

一、开源项目简介 高度可定制零售供应链中台基础系统&#xff0c;集成零售管理, 电子商务, 供应链管理, 财务管理, 车队管理, 仓库管理, 人员管理, 产品管理, 订单管理, 会员管理, 连锁店管理, 加盟管理, 前端React/Ant Design, 后端Java Spring自有开源框架&#xff0c;全面支…

软件测试之黑盒测试的具体方法详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一.基于需求的设计方法二.等价类三.边界值四.判定表4.1 **关系**4.2 如何设计测试用例4.3 实际案例第一步第二步第三步第四步 五.正交排列5.1 什么是正交表5.2 …

shell脚本的判断式

文章目录 shell脚本的判断式利用test命令的测试功能关于某个文件名的【文件类型】判断关于文件的权限检测两个文件之间的比较关于两个整数之间的比较判定字符串的数据多重条件判定例题 利用判断符号[ ]例题 shell脚本的默认变量($0、$1...)例题shift&#xff1a;造成参数变量号…

Linux安装Mysql操作步骤详解

目录 1. 检测当前系统中是否安装了MySql数据库 2. 使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux 3. 解压并解包到/usr/local/mysql&#xff08;便于区分&#xff09; 第一步&#xff1a;将包先移动到该目录下 第二步&#xff1a;解压解包 第三步&#xff1a…

LeetCode 105.106. 从前序|后序与中序遍历序列构造二叉树 | C++语言版

LeetCode 105. 从前序与中序遍历序列构造二叉树 | C语言版 LeetCode 105. 从前序与中序遍历序列构造二叉树题目描述解题思路思路一&#xff1a;使用递归代码实现运行结果参考文章&#xff1a; 思路二&#xff1a;减少遍历节点数代码实现运行结果参考文章&#xff1a; LeetCode …

C语言复习笔记1

1.不同数据类型所占字节数。 bit 01二进制的比特位 byte 字节 8 bit 比特 之后的单位都是以1024为倍数 #include<stdio.h> #include<unistd.h>int main() {printf("sizeof(char)%d\n",sizeof(char));printf("sizeof(short)%d\n",sizeof(sh…

JavaScript 笔记

1 简介 JavaScript 诞生于1995年&#xff0c;是由网景公司发明&#xff0c;起初命名为LiveScript&#xff0c;后来由于SUN公司的介入&#xff0c;更名为 JavaScript。1996年微软在其最新的IE3浏览器中引入了自己对JavaScript的实现JScript&#xff0c;于是市面上就存在两个版本…