Tree搜索二叉树、map和set_数据结构

数据结构专栏
如烟花般绚烂却又稍纵即逝的个人主页
本章讲述数据结构中搜索二叉树与HashMap的学习,感谢大家的支持!欢迎大家踊跃评论,感谢大佬们的支持!
在这里插入图片描述

目录

  • 搜索二叉树的概念
    • 二叉树搜索模拟实现
        • 搜索二叉树查找
        • 搜索二叉树插入
        • 搜索二叉树删除
  • HashMap 和HashSet的定义
    • hashCode(开散链法)
    • 哈希冲突
        • 模拟实现哈希桶(尾叉法)
        • 模拟创建泛型哈希桶

搜索二叉树的概念

二叉树左边的值小与根节点,右边的值大于根节点。
左树<根节点<右树
这样也大大提升了我们代码搜索的效率
这时通过中序遍历得到一个有序的数组。
在这里插入图片描述

二叉树搜索模拟实现

搜索二叉树查找

给一个值来判断数组中是否包含这个元素。
思想:1.节点不能为空,为空说明没有元素
2.明确左边的数都比跟节点要小,而右边的树比跟节点大,小往左走,大往右走,搜索到返回true,出了条件返回false(没有搜索到此元素)。
在这里插入图片描述

   public boolean search(int val){TreeNode cur=this.root;while(cur!=null){if(val>cur.val){cur=cur.right;}else if(val<cur.val){cur=cur.left;}else{return true;}}return false;}

时间复杂度:最好情况下O(logN)
最坏情况下O(N)——在单分枝的情况下

搜索二叉树插入

如果要插入数据的情况下,插入的数据大于根节点一直走,如果小于根节点则插入左树,如果一直大于则直到为空插入,因为遍历的cur为空出来后没有最后一个节点的位置,在插入之前需要定义一个parent来记录根节点的,来放到左树或者右树。
在这里插入图片描述

  public boolean insert(int val){if(this.root==null){//root为空情况下this.root=new TreeNode(val);return true;}TreeNode cur=this.root;//定义一个值来接收前一个父亲节点值TreeNode parent=null;while(cur!=null){parent=cur;if(cur.val>val){parent=cur;cur=cur.left;} else if (cur.val< val) {parent=cur;cur=cur.right;}else{//不需两个相同元素存在return false;}}TreeNode node=new TreeNode(val);if(parent.val>val){//插入左边parent.left=node;}else{parent.right=node;}return true;}
搜索二叉树删除

当我们要删除树中某一个节点的时候我们要考虑的情况比较多当left为空节点.
这里分三种情况讨论
第一种情况:
1.如果想要删除的节点为root,且左树为空情况下,则直接指向right。
因为parent事cur的上一个节点的记录
2.如果parent的左树为cur且cur的左树为空,则parent.left=cur.right。
3.如果parent的右树是cur且cur的左树为空,则parent.right=cur.right。

在这里插入图片描述

第二种情况:
1当cur==root时且没有右树,则左树为新的根节点。
2.parent指向的左树为cur时,因为cur没有右树则parent.left=cur.left。
3.parent指向的右树为cur时,因cur没有右树则parent.right=cur.left。

在这里插入图片描述

第三种情况:要删除的cur的左右子树都不为空。
如果都不为空,需要找到比左树大,但是比右树要小的值。
如果cur的下一个右树节点的左树存在最小值则直接将其cur覆盖。或者cur的右树没有左树节点,则右树第一个节点覆盖掉cur。

cur的左右树都不为空,则cur是比左树要到,所以不需要考虑cur的左树部分。
定义两个值来标记targetParent和target的右树,从右树的左侧找到最小值,进行覆盖(curParent来作为上一个的父亲节点),这时候要删除target节点,当targetParent的左树为target时,因为target一定是在最后一个左树位置,target的右树赋值给targetParent来取消与target的连接。
如果target为右树则targetParent直接指向target的下一个右树。

  public void  removeThisNode(TreeNode cur,TreeNode parent){if(cur.left==null){//如果cur根节点为要删除的节点,直接将root指向cur.rightif(cur==this.root){this.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){this.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的值被target覆盖掉cur.val=target.val;//这里target的指向修改if(targetParent.left==target){targetParent.left=target.right;}else{targetParent.right=target.right;}}}

时间复杂度O(logN)

HashMap 和HashSet的定义

HashSet是java集合框架中Set的常用类。
HashSet不允许存储重复元素的集合,它使用哈希表来存储元素(val),确保每一个元素是唯一的,时间复杂度为O(1).

HashMap是java集合框架Map的常用类。
HashMap也是用哈希表通过key键值来存储val,与HashMap不同,它通过key键值来存储,元素可以相同,但是key键值一单相同val值就会被覆盖掉。

hashCode(开散链法)

二叉搜索树是通过对半切的方式进行比较,类似于我们的二分法查找,但是它的如果是两边的树是平衡时,时间复杂度是O(logN),如果是一棵单分枝树时间复杂度来到O(N)都要进行遍历。

而哈希可以不经过比较,一次性从想要查找的范围内获取到该元素。
如果想要实现,通过哈希函数使元素的存储位置与它的关键码之间能够建立一一映射的关系,通过公式:hash=key(查找的下标)%capacity(容量)如下图所示:

5%10=5将19到5下标
13%10=3将24放到3下标
15%10=5将52放到5下标的链表的next处
在这里插入图片描述

哈希冲突

而通过上述我们发现,5,15都已经放到了5下标位置,不同关键字通过相同的哈希函数计算出相同的哈希地址
如何避免哈希冲突?
哈希冲突无法直接避免,因为key我们的元素是不能改变的,我们只能控制空间的大小,来减少链表中元素
负载因子 = 表中有效数据个数 / 空间的大小。
>负载因子越大,产出冲突的概率越高,增删查改的效率越低。
负载因子越小,产出冲突的概率越低,增删查改的效率越高

负载因子设定为0.75
当我们的元素个数/空间的长度如果超出0.75,则需要扩容,加大空间,将负载因子缩小,从而让查改效率加强。
在这里插入图片描述

模拟实现哈希桶(尾叉法)

1.这里我们创建一个哈希表来进行搜索,通过数组和链表的方式来构成,让其更快搜索到想要搜索到的值,将下标值放入指定的数组链表中来存储。
2.每个数组的下标对应一个链表,当想要搜索某个下标值时,hash=key%capacity 得到的就是某一下标的链表,通过链表连接该key的每一个元素。
3.判断是否需要大于负载因子(扩容 )
当我们扩容时,通过2*len的长度进行扩容,然后通过key%新定义的数组的容量,给到新的数组链表中,将之前存储的链表指向其他下一个节点即可。
在这里插入图片描述

public class HashBucket {
//内部类static class Node{public int key;public int val;public Node next;//内部类构造方法public Node(int key, int val) {this.key = key;this.val = val;}}//申请一个数组public Node[] array;int size;//长度public static final float loadFactor=0.75f;//负载因子的默认值public HashBucket(){//构造方法this.array=new Node[10];}//放入元素public void put(int key,int val){int index=key%array.length;Node node=new Node(key,val);Node preV=null;//为空if(this.array[index]==null){this.array[index]=node;}else{//不为空Node cur=this.array[index];while(cur!=null){if(cur.key==key){cur.val=val;return;}preV=cur;cur=cur.next;}assert preV!=null;preV.next=node;}size++;if(judgThisLoadFactorFull())//扩容grow();}//判断是否大于负载因子public boolean judgThisLoadFactorFull(){return size*1.0f/array.length>loadFactor;}//扩容private void grow() {Node[] newArray=new Node[2*array.length];//两倍的扩容for(int i=0;i<array.length;i++){Node cur=this.array[i];Node preV=null;while(cur!=null){int index= cur.key%newArray.length;if(newArray[index]==null){newArray[index]=cur;cur=cur.next;this.array[i]=cur;newArray[index].next=null;}else{Node newCur=newArray[index];while(newCur!=null){preV=newCur;newCur=newCur.next;}assert preV!=null;preV.next=cur;cur=cur.next;this.array[i]=cur;preV.next.next=null;}}}this.array=newArray;}//通过key搜索到值public int getValByThisKey(int key){int index=key%this.array.length;Node cur=this.array[index];while (cur!=null){if(cur.key==key){return cur.val;}cur=cur.next;}return -1;}

当我们创建了一个泛型的类型后,生成了hashCode方法,我们生成两个参数相同的对象时,如果将student1放入到hashmap中,当我们想要查找hashmap1中的值时,使用student2也可以查到student1中的值,这里的哈希函数通过计算关键码,因为两者的关键码相同,得到关键码的数值。

 Student student1=new Student("12313");Student student2=new Student("12313");System.out.println(student1.hashCode());System.out.println(student2.hashCode());HashMap<Student,Integer> hashMap=new HashMap<>();hashMap.put(student1,2);System.out.println(hashMap.get(student2));

在这里插入图片描述
而我们如何自己模拟实现一个自定义类型的哈希桶呢?
接下来我们实现以下

模拟创建泛型哈希桶

这里泛类型哈希桶实现与上述哈希桶实现类似,但是这里注意get方法中的比较关键码是通过equals来判断

public class HashBucket<K,V>{static class Node<K,V>{public K key;public V val;public Node<K,V> next;public Node(K key, V val) {this.key = key;this.val = val;}}public Node<K,V>[] array;public int usedSize;public static final float DefaultFactor=0.75f;public HashBucket(){this.array=(Node<K, V>[]) new Node[10];}//放入值public void put(K key,V val){int hash=key.hashCode();int index=hash%array.length;Node<K,V> cur=array[index];Node<K,V> node=new Node<>(key,val);Node<K,V> preV=null;if(cur==null){this.array[index]=node;}else{while(cur!=null){if(cur.key==key){cur.val=val;}preV=cur;cur=cur.next;}preV.next=node;}usedSize++;}//获取值public V get(K key){int hash= key.hashCode();int index=hash % array.length;Node<K,V> cur=this.array[index];while(cur!=null){//这里比较不是==if(cur.key.equals(key)){return cur.val;}cur=cur.next;}return null;}
}

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

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

相关文章

Swift实现高效链表排序:一步步解读

文章目录 前言摘要问题描述题解解题思路Swift 实现代码代码分析示例测试与结果 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 148. 排序链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流…

【开篇】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

qt QAnimationDriver详解

1、概述 QAnimationDriver是Qt框架中提供的一个类&#xff0c;它主要用于自定义动画帧的时间控制和更新。通过继承和实现QAnimationDriver&#xff0c;开发者可以精确控制动画的时间步长和更新逻辑&#xff0c;从而实现丰富和灵活的动画效果。QAnimationDriver与QAbstractAnim…

何时在 SQL 中使用 CHAR、VARCHAR 和 VARCHAR(MAX)

在管理数据库表时&#xff0c;考虑 CHAR、VARCHAR 和 VARCHAR(MAX) 是必不可少的。此外&#xff0c;使用正确的工具&#xff08;例如dbForge Studio for SQL Server&#xff09; &#xff0c;与数据库相关的任务都会变得更加容易。它是针对 SQL Server 专业人员的强大的一体化解…

20241127 给typecho文章编辑附件 添加视频 图片预览

Typecho在写文章时&#xff0c;如果一次性上传太多张图片可能分不清哪张&#xff0c;因为附件没有略缩图&#xff0c;无法实时阅览图片&#xff0c;给文章插入图片时很不方便。 编辑admin/file-upload.php 大约十八行的位置 一个while 循环里面,这是在进行html元素更新操作,在合…

Linux命令系列-常见查看系统资源命令

Linux命令系列-常见查看命令 进程管理内存管理磁盘空间管理网络管理主机系统 摘要&#xff1a;本文将对linux系统上常见的查看系统各种资源的命令进行介绍&#xff0c;包括du&#xff0c;df&#xff0c;netstat等命令。所有这些命令都有相关实验截图&#xff0c;实验平台为ubun…

【Python网络爬虫笔记】6- 网络爬虫中的Requests库

一、概述 Requests 是一个用 Python 语言编写的、简洁且功能强大的 HTTP 库。它允许开发者方便地发送各种 HTTP 请求&#xff0c;如 GET、POST、PUT、DELETE 等&#xff0c;并且可以轻松地处理请求的响应。这个库在 Python 生态系统中被广泛使用&#xff0c;无论是简单的网页数…

SolarCube: 高分辨率太阳辐照预测基准数据集

太阳能作为清洁能源在减缓气候变化中的作用日益凸显&#xff0c;其稳定的供应对电网管理至关重要。然而&#xff0c;太阳辐照受云层和天气变化的影响波动较大&#xff0c;给光伏电力的管理带来挑战&#xff0c;尤其是在调度、储能和备用系统管理方面。因此&#xff0c;精确的太…

对拍详细使用方法

对拍的作用 对于我们在学校OJ&#xff0c;cf&#xff0c;牛客…各种只提供少量测试数据的题目&#xff0c;常常交上代码常常超时&#xff0c;能写出正确的暴力代码而题目要求的时间复杂度更低。然而这时你写出了能通过样例且时间复杂度更低的代码&#xff0c;但交上去就是错误…

玄机应急:Apache日志分析Mysql应急Redis应急

目录 第二章&#xff1a;Linux的Apache日志分析 1、提交当天访问次数最多的IP&#xff0c;即黑客IP 2、黑客使用的浏览器指纹是什么&#xff0c;提交指纹的md5 3、查看index.php页面被访问的次数&#xff0c;提交次数&#xff1a; 4、查看黑客IP访问了多少次&#xff0c;提…

使用easyexcel导出复杂模板,同时使用bean,map,list填充

背景 在使用easyexcel导出时&#xff0c;如果遇到一个模板中同时存在 一部分是实体类中的字段&#xff0c;另外部分是列表的字段&#xff0c;需要特殊处理一下&#xff0c;比如下面的模板&#xff1a; 这里面 user&#xff0c; addr 是实体类&#xff08;或者map&#xff09…

otter 扩展

参见otter官方的说明&#xff1a;数据处理自定义&#xff0c;比如Extract , Transform的数据处理. 目前Select/Load不支持数据自定义处理。 Extract模块&#xff1a; 1.EventProcessor : 自定义数据处理&#xff0c;可以改变一条变更数据的任意内容。 2.FileResolver : 解决数…

STM32的CAN波特率计算

公式&#xff1a; CAN波特率 APB总线频率 / &#xff08;BRP分频器 1&#xff09;/ (SWJ BS1 BS2) SWJ一般为1。 例如STM32F407的&#xff0c;CAN1和CAN2都在在APB1下&#xff0c;频率是42000000 如果想配置成1M波特率&#xff0c;则计算公式为&#xff1a;

Z2400039基于Java-+ SpringBoot + vue 企业信息管理系统的设计与实现(源码 配置 PPT 文档 分享)

企业信息管理系统 1.项目描述2.项目结构后端&#xff08;Spring Boot&#xff09;前端&#xff08;Vue.js Element UI&#xff09; 2. 功能实现登录页首页系统管理岗位管理部门管理 3. 部署和运行注意事项 4.界面展示5.源码获取 1.项目描述 基于你的描述&#xff0c;这个项目…

hhdb数据库介绍(10-20)

监控 监控面板 监控面板为用户提供计算节点、服务器相关的监控功能&#xff0c;包含&#xff1a;计算节点服务状态、计算节点流量、计算节点服务器资源、其他服务器资源。 数据采集说明&#xff1a; 监控面板显示24小时内采集的数据&#xff08;需要放大显示&#xff0c;正…

医学机器学习:数据预处理、超参数调优与模型比较的实用分析

摘要 本文介绍了医学中的机器学习&#xff0c;重点阐述了数据预处理、超参数调优和模型比较的技术。在数据预处理方面&#xff0c;包括数据收集与整理、处理缺失值、特征工程等内容&#xff0c;以确保数据质量和可用性。超参数调优对模型性能至关重要&#xff0c;介绍了多种调…

SystemUI 下拉框 Build 版本信息去掉

需求及场景 去掉SystemUI 下拉框 Build 版本信息 如下图所示&#xff1a;去掉 12 &#xff08;SP1A.201812.016) 了解 去掉之前我们先了解它是个什么东西:其实就是一个Build RTM 信息显示 Android_12_build_SP1A.210812.016 修改文件 /frameworks/base/packages/Syste…

transformer学习笔记-词嵌入embedding原理

.在学习transformer的时候&#xff0c;可以看到&#xff0c;输入通常需要对词token进行embedding处理&#xff0c;如果没有先了解embedding的原理可能会有疑问&#xff0c;这个embedding&#xff0c;到底怎么来的&#xff0c;怎么就把一个token 变成一个矩阵&#xff0c;这个矩…

Apache Airflow 快速入门教程

Apache Airflow已经成为Python生态系统中管道编排的事实上的库。与类似的解决方案相反&#xff0c;由于它的简单性和可扩展性&#xff0c;它已经获得了普及。在本文中&#xff0c;我将尝试概述它的主要概念&#xff0c;并让您清楚地了解何时以及如何使用它。 Airflow应用场景 …

python+django自动化部署日志采用‌WebSocket前端实时展示

一、开发环境搭建和配置 # channels是一个用于在Django中实现WebSocket、HTTP/2和其他异步协议的库。 pip install channels#channels-redis是一个用于在Django Channels中使用Redis作为后台存储的库。它可以用于处理#WebSocket连接的持久化和消息传递。 pip install channels…