二叉搜索树

news2025/1/6 20:16:20

文章目录

  • 二叉搜索树
  • 1. 概念
  • 2. 模拟实现二叉搜索树
    • 2.1 准备工作 创建类
    • 2.2 查找方法
    • 2.3 插入方法
    • 2.4 删除方法
  • 3. 性能分析

二叉搜索树


前言 :

在这里插入图片描述

1. 概念


二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

在这里插入图片描述

概念啥的看看就行了,之前二叉树的时候可能就已经见过了, 下面我们直接来实现我们自己的二叉搜索树

2. 模拟实现二叉搜索树

2.1 准备工作 创建类


这里我们创建一个 BinarySearchTree 和 内部类 TreeNode
在这里插入图片描述

2.2 查找方法

在这里插入图片描述


代码实现 :

查找功能就完成了,下面完成插入方法

2.3 插入方法

在这里插入图片描述


补充: 这里我们 假设我们的二叉搜索树是一颗完全二叉树,那么这里我们插入的时间复杂度是不是就是O(logN)

在这里插入图片描述


单分支的情况 加 了解 AVL 树
在这里插入图片描述


补充 : 这里忘记 讲 了 这里 二叉搜索树是空树的情况,那么我们直接让 root = new TreeNode(val) 即可,创建第一个节点


最终代码 :

 public boolean insert(int val) {
        if (root == null) {
            root = new TreeNode(val);
        }
        TreeNode cur = root;
        //定义一个 parent 指向 cur的 上一个根节点
        TreeNode parent = null;
        while (cur != null) {

            if (cur.val < val) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > val) {
                parent = cur;
                cur = cur.left;
            } else {
                return false;
            }
        }
        // 此时判断 当前的val 是大于 parent.val 还是小于
        if (parent.val < val) {
            // 此时 根据二叉搜索树的性质大于根 放在右树
            parent.right = new TreeNode(val);
        }
        if (parent.val > val) {
            // 此时 val 小于 parent.val 插入左树
            parent.left = new TreeNode(val);
        }
        return true;
    }

下面就来学习一下,二叉搜索树中难一点的方法删除

2.4 删除方法

删除操作,算我们实现二叉搜索树中唯一难一点的操作这里需要分三种情况

图一:

在这里插入图片描述


图二 : cur.left == null

在这里插入图片描述


图三 : cur.right == null

在这里插入图片描述


图四 : cur.left != null && cur.right != null

在这里插入图片描述


这里在右树中找最小的 可以自己画图分析 ,因为是一样的, 这里就留一个作业, 或者看下面的代码实现, 我们图是以找左树最大的,代码以找右树最小的 。


图一 :
在这里插入图片描述


图二 :

在这里插入图片描述


删除总代码:

 // 写一个方法找到我们需要删除的节点 和 根节点
    public void remove(int key) {
        //找 parent 和 cur 节点
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {

            if (cur.val < key) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > key) {
                parent = cur;
                cur = cur.left;
            } else {
                // 此时找到了我们的 cur ,和 parent
                removeNode(cur, parent);
                break;
            }
        }
    }

    public void removeNode(TreeNode cur, TreeNode parent) {
        // 1. 当 cur.left == null  的情况
        if (cur.left == null) {
            // 此时又分为三种情况
            if (cur == root) {
                root = root.right;
                // cur.left == null ,所以直接让 root 等于右树
            } else if (parent.left == cur) {
                // 根据图的分析,
                parent.left = cur.right;
            } else {
                // 此时 parent.right = cur
                parent.right = cur.right;
            }
        } else if (cur.right == null) {
            // 此时 cur.right 同样有三种情况
            if (cur == root) {
                root = root.left;
            } else if (parent.left == cur) {
                parent.left = cur.left;
            } else {
                // parent.right = cur
                parent.right = cur.left;
            }

        } else {
            // cur.left != null && cur.right != null  这里我们使用方法二
            // 在cur的右树中找 最小的
            TreeNode parentDummy = cur;
            TreeNode curDummy = cur.right;
            while (curDummy.left != null) {
                parentDummy = curDummy;
                curDummy = curDummy.left;
            }
            cur.val = curDummy.val;
            // 此时找到了最小的 判断两种情况即可
            //  curDummy.left == null
            if (parentDummy.left == curDummy) {
                parentDummy.left = curDummy.right;
            } else {
                //parentDummy.right = curDummy
                parentDummy.right = curDummy.right;
            }
        }


    }

此时我们的二叉搜索的 查找新增删除方法就完成了.

附上代码:

public class BinarySearchTree {
    static class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode root;

    public TreeNode search(int key) {
        TreeNode cur = root;
        while (cur != null) {
            if (cur.val < key) {
                // 此时 key 大于 根进入 右树找
                cur = cur.right;
            } else if (cur.val > key) {
                // 此时 ken 小于 根进入 左树找
                cur = cur.left;
            } else {
                // 此时说明找到了 返回 当前节点地址;
                return cur;
            }
        }
        // 此时说明没有找到
        return null;
    }

    public boolean insert(int val) {
        if (root == null) {
            root = new TreeNode(val);
        }
        TreeNode cur = root;
        //定义一个 parent 指向 cur的 上一个根节点
        TreeNode parent = null;
        while (cur != null) {

            if (cur.val < val) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > val) {
                parent = cur;
                cur = cur.left;
            } else {
                return false;
            }
        }
        // 此时判断 当前的val 是大于 parent.val 还是小于
        if (parent.val < val) {
            // 此时 根据二叉搜索树的性质大于根 放在右树
            parent.right = new TreeNode(val);
        }
        if (parent.val > val) {
            // 此时 val 小于 parent.val 插入左树
            parent.left = new TreeNode(val);
        }
        return true;
    }

    // 写一个方法找到我们需要删除的节点 和 根节点
    public void remove(int key) {
        //找 parent 和 cur 节点
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {

            if (cur.val < key) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > key) {
                parent = cur;
                cur = cur.left;
            } else {
                // 此时找到了我们的 cur ,和 parent
                removeNode(cur, parent);
                break;
            }
        }
    }

    public void removeNode(TreeNode cur, TreeNode parent) {
        // 1. 当 cur.left == null  的情况
        if (cur.left == null) {
            // 此时又分为三种情况
            if (cur == root) {
                root = root.right;
                // cur.left == null ,所以直接让 root 等于右树
            } else if (parent.left == cur) {
                // 根据图的分析,
                parent.left = cur.right;
            } else {
                // 此时 parent.right = cur
                parent.right = cur.right;
            }
        } else if (cur.right == null) {
            // 此时 cur.right 同样有三种情况
            if (cur == root) {
                root = root.left;
            } else if (parent.left == cur) {
                parent.left = cur.left;
            } else {
                // parent.right = cur
                parent.right = cur.left;
            }

        } else {
            // cur.left != null && cur.right != null  这里我们使用方法二
            // 在cur的右树中找 最小的
            TreeNode parentDummy = cur;
            TreeNode curDummy = cur.right;
            while (curDummy.left != null) {
                parentDummy = curDummy;
                curDummy = curDummy.left;
            }
            cur.val = curDummy.val;
            // 此时找到了最小的 判断两种情况即可
            //  curDummy.left == null
            if (parentDummy.left == curDummy) {
                parentDummy.left = curDummy.right;
            } else {
                //parentDummy.right = curDummy
                parentDummy.right = curDummy.right;
            }
        }


    }

    public void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        // 中序遍历 左 -> 根 -> 右
        inorder(root.left);
        System.out.print(root.val + " ");
        inorder(root.right);
    }
}


下面我们测试一下

在这里插入图片描述

完美

3. 性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树

在这里插入图片描述


最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:

最差情况下,二叉搜索树退化为单支树,其平均比较次数为:

问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插入关键码,都可以

是二叉搜索树的性能最佳?

这里学习二叉搜索树 ,主要是为下文的 SetMap 做准备

TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树,而红黑树是一棵近似平衡的

二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证,这里红黑树比较难,需要我们知识的沉淀 ,那么再后续再来说我们的AVL树和红黑树…

下文 : Map 和 Set

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

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

相关文章

学点高端技术:基于密度的聚类算法——FDBSCAN算法

机器学习、人工智能各类KNN算法层出不穷&#xff0c;DBSCAN具有强代表性&#xff0c;它是一个基于密度的聚类算法&#xff0c;最大的优点是能够把高密度区域划分为簇&#xff0c;能够在高噪声的条件下实现对目标的精准识别&#xff0c;但该算法当前已远不能满足人们对于高效率、…

零基础自学javase黑马课程第二天

零基础自学javase黑马课程第二天 ✨欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ &#x1f52e;本文由京与旧铺原创&#xff0c;csdn首发&#xff01; &#x1f618;系列专栏&#xff1a;java学习 &#x1f4bb;首发时间&#xff1a;&#x1f39e;2022年10月16日&#…

【电子技术基础(精华版)】直流稳压电路

前期我们了解了一些关于直流稳压电源的基础知识&#xff0c;为了更好地完善职教高考电子技术专业的需求&#xff0c;接下来我会更新【电子技术基础&#xff08;精华版&#xff09;】&#xff0c;从中可以让更多的职教高考生有效地复习。 由于本人是山东省的一位博主&#xff0…

3、SySeVR测试(上)

一、准备 1、将测试代码放在/home/test目录下&#xff1b; 2、将测试数据导入joern 在/home/SySeVR/joern-0.3.1查看是否存在.joernIndex文件&#xff0c;有的话&#xff0c;需要删除。 删除之后&#xff0c;将测试数据导入joern: java -jar /home/SySeVR/joern-0.3.1/bin/jo…

程序员的中年危机:那些能工作到45、50、60的程序员们,究竟具备了哪些能力?

程序员行业新技术发展迅猛&#xff0c;可以说是日新月异。也正是这个原因&#xff0c;中年危机成为我们必须面对和攻克的问题。 思考一个问题&#xff1a;那些能工作到45、50、甚至60的程序员们&#xff0c;究竟具备了哪些过人的能力&#xff1f; 就我过去的经历和观察来说&a…

A comprehensive overview of knowledge graph completion

摘要 知识图(KG)以其代表和管理海量知识的独特优势&#xff0c;为各种下游知识感知任务(如推荐和智能问答)提供了高质量的结构化知识。KGs的质量和完整性在很大程度上决定了下游任务的有效性。但由于知识产权制度的不完备性&#xff0c;知识产权制度中仍有大量有价值的知识缺失…

【《机器人技术》复习】

【《机器人技术》复习】1. 要求&#xff1a;2. 机械手运动解算问题2.1 自由度考点2.2 运动学方程2.3 动力学方程2.4 传感器2.5 编程题1. 要求&#xff1a; 本次大作业上交截止时间 之前&#xff0c;超时&#xff0c;本门课程判定不及格。 作业上交的格式如下 一律以 WORD 文档…

2022年江西省职业院校技能大赛“网络空间安全”比赛任务书

2022年江西省职业院校技能大赛“网络空间安全” 比赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 A-5 …

求交叉链表头结点-面试必备

这里分享一下一个交叉链表的关键题目&#xff0c;觉得不错的小伙伴别忘了点赞支持 交叉链表无环链表思路代码有环链表思路代码总结无环链表 已知有两个链表&#xff08;无环&#xff09;相交&#xff0c;求出相交的头结点 思路 因为链表相交&#xff0c;所以最后一部分一定重…

每天五分钟机器学习:常用的参数寻优方法——k折交叉验证

本文重点 本文我们介绍一种常用的参数寻优方法--k折交叉验证&#xff0c;现在的数据集一般分为三类&#xff0c;分别为训练集&#xff0c;验证集&#xff0c;测试集。训练集用于训练模型&#xff0c;验证集用于调参&#xff0c;测试集用于测试调参之后的模型效果。 但是很多时…

SpringBoot+Vue实现前后端分离社区疫苗接种管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JDK版…

xray和burp联动

目录 xray下载安装CT Stack 安全社区 Burp和xray联动 xray下载安装下载地址&#xff1a;CT Stack 安全社区 先通过PowerShell打开xray所在的目录&#xff0c;运行&#xff0c;生成yaml文件 genca在目录下生成证书 生产证书后将证书导入浏览器 导入后在本地安装一下 Burp和xray…

WebdriverIO – 完整的初学者课程2022

WebdriverIO – 完整的初学者课程2022 从零开始学习和使用 JavaScript 实现 Webdriver IO&#xff01;构建功能齐全的 Web 测试自动化框架 课程英文名&#xff1a;WebdriverIO - Complete Beginner Course 2022 此视频教程共1.0小时&#xff0c;中英双语字幕&#xff0c;画质…

SD-WAN不断冲击传统WAN架构

随着全球化数字信息转型&#xff0c;网络结构也是在不断的发展和完善。随着云时代的到来&#xff0c;传统的网络布局的局限性开始凸显出来。在过去几年广域网最重要的变化是软件定义广域网技术 (SD-WAN) 的广泛部署&#xff0c;它改变了网络专业人员优化和保护广域网连接的方式…

python基于PHP+MySQL的大学生宿舍管理系统

大学宿舍管理系统是信息时代的产物,它是学校宿管部门的一个好帮手。有了它不再需要繁重的纸质登记,有了它宿管员不在需要繁重的工作,一些公寓信息和住宿等基本信息可以由管理人员及时的对信息进行查询、更新、修改和删除,方便简易,且时效性高 基于PHP大学生宿舍管理系统采用当前…

年薪50w+的软件测试工程师是怎么炼成的?

随着互联网行业的迅速发展&#xff0c;软件测试工程师的地位越来越高&#xff0c;公司招聘时的薪资也越来越高&#xff0c;那么市场上为什么还有大量的软件测试工程师薪资只有5-6k呢&#xff1f;因为他们有一个共同的弱点&#xff0c;就是只会手工测试&#xff01;&#xff01;…

Python编程运算符 比较运算符

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.比较运算符 二.比较运算符使用 &#xff08;1&#xff09;等于 &…

操作系统之保护模式

保护模式保护模式概述初见保护模式保护模式之寄存器扩展保护模式之寻址扩展全局描述符表段描述符全局描述符GDT&#xff0c;局部描述符LDT级选择子保护模式的开关&#xff0c;CR0寄存器的PE位进入保护模式保护模式概述 ** 问题1&#xff1a;为什么会有保护模式** 实模式下操作…

D-逃亡的贝贝(二分+有限制最小边权)

D-逃亡的贝贝_牛客练习赛104 (nowcoder.com) 题意:给你一个n个点,m条双向边的图(有边权),再给你起点s与终点t,以及有k个药水可以使某一条边,减小,求起点到终点经历边权最小值为多少. 题解: 首先建图,然后看到题中让我们找的是一个最小,或最大的值,是一个线性的值,我们就可以想…

整理了几个100%提高Python代码质量的技巧,直呼过瘾

B站|公众号&#xff1a;啥都会一点的研究生 相关阅读 整理了几个100%会踩的Python细节坑&#xff0c;提前防止脑血栓 整理了十个100%提高效率的Python编程技巧&#xff0c;更上一层楼 Python-列表&#xff0c;从基础到进阶用法大总结&#xff0c;进来查漏补缺 Python-元组&…