JAVASE进阶:Collection高级(3)——HashSet、LinkedHashSet底层原理

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:JAVASE进阶:Collection高级(2)——源码剖析ArrayList、LinkedList、迭代器
📚订阅专栏:JAVASE进阶
希望文章对你们有所帮助

Set是Collection的另一个实现接口,与List相比,Set是无索引、元素不重复的,HashSet、LinkedHashSet以及TreeHashSet都是很常用的,在这里会弄懂一下HashSet以及LinkedHashSet的底层原理。
在这里就先不系统跟踪源码了,因为更值得跟踪的实际上是Map类的(HashMap、TreeMap等)。

HashSet、LinkedHashSet底层原理

  • 红黑树
    • 定义
    • 红黑规则
    • 添加结点规则
  • HashSet底层原理
    • 概述
    • JDK8以前的工作过程
    • JDK8以后的工作过程
    • 问题
  • LinkedHashSet底层原理

红黑树

在学习之前,简单看一下红黑树,我这里是一种复习,讲的不是很详细,要吃透红黑树需要自己先去系统学习一下。

定义

红黑树又叫平衡二叉B树,是一种特殊的二叉查找树,红黑树每个结点都有存储位表示结点的颜色。

每一个节点可以是红或者黑;红黑树不是高度平衡的,它的平衡是通过"红黑规则"进行实现的。

红黑树是二叉查找树,红黑规则不像平衡二叉树那样每次高度差超过1就旋转,那样会导致插入数据的效率变慢。

红黑规则

1、每一个结点要么红色要么黑色
2、根结点必须是黑色
3、若一个结点没有子结点或父节点,则该结点相应的指针属性值为Nil,这些Nil视为叶结点,每个叶结点(Nil)是黑色的
4、若某一个结点是红色的,则其子结点必须是黑色(即不能出现两个红结点相连的情况)
5、对每个结点,从该结点到其所有后代结点的简单路径上,均包含相同数目的黑色结点。

添加结点规则

1、添加结点时默认颜色为红色(效率会更高,如果是黑色的,会经常违背红黑规则的第5条规则)
2、添加根结点,直接变为黑色
3、添加非根结点,若父亲为黑色,则不需要任何操作
4、添加非根结点,若父亲为红色,则:
(1)叔叔为红色:
①将“父”设为黑,将“叔叔”设为黑
②将“祖父”设为红
③若祖父为根,再将根变回黑色
④若祖父非根,将祖父设置为当前结点再进行其他判断
(2)叔叔黑色,当前结点是父的右孩子,则把父作为当前结点并左旋,再进行判断
(3)叔叔黑色,当前结点是父的左孩子:
①将“父”设为黑色
②将“祖父”设为红色
③以“祖父”为支点进行右旋

HashSet底层原理

概述

HashSet有以下的特点:无序、不重复、无索引。
HashSet底层采用哈希表存储数据,JDK8以前,哈希表=数组+链表;JDK8开始,哈希表=数组+链表+红黑树。哈希表的核心是哈希值(对象的整数表现形式)。

哈希表最开始是一个长度为16,值全为null的数组,当要添加数据的时候,不是从0索引开始的,而是根据表达式
KaTeX parse error: Expected 'EOF', got '&' at position 24: …x = (数组长度 - 1) &̲ 哈希值
来确定数据存入的位置的。

哈希值

1、根据hashCode方法计算出来的int类型整数
2、该方法定义在Object类,所有对象都可以调用,默认使用地址值来进行计算
3、一般情况下,会冲洗的hashCode方法,利用对象内部的属性值来计算哈希值

对象的哈希值特点

1、若没有重写hashCode方法,则不同对象计算出的哈希值不同(因为默认使用的地址值肯定不相等)
2、若已经重写了hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
3、在小部分情况下,不同属性值或不同地址值算出来的哈希值是一样的,即哈希碰撞

想必大家都是学过哈希算法的,上面内容就不细说了。

JDK8以前的工作过程

JDK8以前,哈希表是数组+链表,工作过程如下:
1、创建一个默认长度为16、默认加载因子为0.75的数组,数组名为table
2、根据元素的哈希值与数组的长度计算出应存入的位置(index = (数组长度 - 1) & 哈希值)
3、判断当前位置是否为null,是则直接存入
4、若当前位置不为null,表示有元素,则调用equals方法比较属性值
5、equals方法判断是一样的,就不存储,如果不一样,就存入这个位置,形成链表

需要注意的是:

加载因子决定了哈希表的扩容时机,当数组中有16 * 0.75 = 12的空间被占用,数组会扩容成原来的2倍
JDK8以前,形成链表的方式是将新元素存入数组,老元素挂在新元素下面

JDK8以后的工作过程

JDK8开始,哈希表是数组+链表+红黑树

比起之前,大致的流程是一样的,但是细节上有些不一样:

JDK8以后,形成链表的方式是直接将新元素挂在老元素下面
数组长度 ≥ 64,且当前位置的链表长度 > 8时,当前的链表就会自动转换成红黑树,从而提高效率

因此,我们集合中存储自定义对象时,必须重写hashCode和equals方法。

问题

摸清原理就可以思考一些问题:
1、HashSet为什么存和取的顺序不一致?

HashSet的遍历是先遍历数组,每次到了数组的某个位置以后,把这个位置的链表或红黑树遍历过去,显然这种遍历出来的顺序不一定代表了存储的顺序,因为存储的方式是根据计算公式来的

2、HashSet为什么没有索引?

因为底层不纯粹,挂了红黑树或链表,不好再限定索引,因此舍弃索引

3、HashSet利用什么机制保证数据去重?

(1)用HashCode得到哈希值
(2)用哈希值确定当前元素应该被添加到数组中的哪个位置
(3)用equals比较这个位置的链表或红黑树中元素和新增元素是否相同,相同就不存入,从而实现去重

LinkedHashSet底层原理

LinkedHashSet有以下的特点:有序、不重复、无索引

LinkedHashSet其实底层数据结构还是哈希表,只是对于存入哈希表中的每个元素,都会按照存储的顺序去构建双链表,因此LinkedHashSet是有序的。

如果以后要数据去重,默认用HashSet,如果还要求有序,就需要LinkedHashSet。

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

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

相关文章

STM32 自学笔记 学习笔记 一

起源,A7,A9,M3,原来弄了A9的TQ2440,结果还得来重新熟悉下32函数JLINK使用SW方式,本来可以下载,但是一根线掉了重新上去,就出各种跟线无关问题,干脆把32断了重新接,结果就成功了&…

C++ 免费代码质量扫描分析工具软件

C有许多免费的代码质量扫描分析工具软件,下面是一些比较流行的选择: Cppcheck:这是一个静态分析工具,用于检测C代码中的内存泄漏、未初始化的变量、数组越界等问题。Cppcheck可以检测出常见的和很难发现的缺陷,并且它…

Linux权限【超详细】

📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 目录 扩展知识&#xff1a…

初识webpack(一)概念、入口配置、输出配置、loader等

目录 (一)概念 webpack的依赖图 (二)webpack的基本使用 (三)webpack的配置文件 1.入口(entry)配置 2.输出(output)配置 (三)loader 1.css文件处理 (1)安装css-loader和style-loader (2)在webpack.config.js中配置loader 2.less文件处理 3.postcss的使用 (1)安装…

深入理解K均值算法:Python中的应用与实践

目录 写在开头1. K均值算法基础1.1 什么是K均值算法?1.2 K均值算法的工作原理1.3 算法的优势与局限性 2. K均值算法的实现步骤2.1 初始聚类中心的选择方法2.1.1 随机选择初始中心点2.1.2 K均值算法 2.2 数据点与聚类中心的距离计算2.2.1 欧氏距离计算2.2.2 曼哈顿距…

记录一下怎么重装服务器

使用腾讯的镜像 https://market.cloud.tencent.com/products/35788 首先配置mysql 没有user表,怎么办。 首先创建一个能让外部连接的用户, GRANT ALL PRIVILEGES ON *.* TO myuser% IDENTIFIED BY mypassword WITH GRANT OPTION; 然后修改root密码…

MySQL-----约束

目录​​​​​ 约束 一 主键约束 1-1 操作-添加单列主键 1-2 操作-添加多列主键 1-3 修改表结构添加主键 1-4 删除主键约束 二 自增长约束 2-1 指定自增长字段的初始值 2-2 删除自增列 三 非空约束 3-1 创建非空约束 3-2 删除非空约束 四 唯一约束…

android 设置未知来源等 AppOpsManager 权限的设置接口

开始客户让我们执行下面的CMD 代码 adb shell appops set com.android.chrome REQUEST_INSTALL_PACKAGES allow 后来 GTP 告诉我有 Setmode的方法,后面在设置里面找到了 OP_REQUEST_INSTALL_PACKAGES 这个,里面有个方法mAppOpsManager.setMode(AppOp…

寒假作业2月4号

第三章 类与构造函数 一.选择题 1、下列不能作为类的成员的是(B) A. 自身类对象的指针 B. 自身类对象 C. 自身类对象的引用 D. 另一个类的对象 2、假定AA为一个类,a()为该类公有的函数成员,x为该类的一个对象&am…

SpringCloud + Nacos环境下抽取Feign独立模块并支持MultipartFile

文章目录 一、前提条件和背景1. 前提2. 背景 二、Feign模块1. 依赖引入2. application.yaml配置3. 扩展支持MultipartFile4. 将media-api注册到feign 三、Media模块四、Content模块1. 引入依赖2. 启用FeignClient3. 测试 五、需要澄清的几点 一、前提条件和背景 1. 前提 已经…

反洗钱_1_反洗钱的相关概念

文章目录 一、反洗钱的相关概念1.1 洗钱1.1.1洗钱(Money Laundering)的由来1.1.2 洗钱的概念1.1.3 洗钱的基本过程 1.2 反洗钱 一、反洗钱的相关概念 1.1 洗钱 1.1.1洗钱(Money Laundering)的由来 20世纪20年代,美国芝加哥一个叫做卡蓬特的犯罪集团,以…

谷粒商城-P19

项目结构创建&提交到码云 数据库初始化 保持docker数据库一直打开 docker update redis --restartalways 连不上了,发现配置文件错了 换了一个配置文件。 快速开发 使用开源的脚手架 人人开源 (gitee.com) 使用renren-fast作为后台开发,使用…

Axure RP9原型设计工具使用记录:实际应用及问题记录

Axure RP9使用记录二 📚第三章 实际应用📗快速归位00坐标📗动态菜单📗填充图片📗下拉框联动📗单选框📗全局变量 ⁉️问题记录❓问题一:菜单不显示❗解决方式:调整菜单元件…

elasticsearch 索引模版

当需要为同一类索引应用相同的配置、映射、别名时,如果每次创建索引都逐一配置会有些麻烦。索引模板的出现正是为了简化这种操作,使用索引模板你可以方便地为某一类索引自动配置某些共同的参数 使用索引模版定制索引结构 假如你想在Elasticsearch中创建…

深入Spring MVC的工作流程

深入Spring MVC的工作流程 在Spring MVC的面试问题中,常常被询问到的一个问题。Spring MVC的程序中,HTTP请求是如何从开始到结束被处理的。为了研究这个问题,我们将需要深入学习一下Spring MVC框架的核心过程和工作流程。 1. 启动请求生命周…

【UE5 C++】超详细虚幻C++零基础学习教程

B站免费教程,虚幻C零基础教学入门级视频,帮助大家学习虚幻C。 视频地址:【虚幻5】UE5C零基础全网全流程开发从入门到进阶教程合集(持续跟新中)_哔哩哔哩_bilibili 课程介绍视频如下 【虚幻5】UE5C零基础全网全流程开…

[python]基于LSTR车道线实时检测onnx部署

【框架地址】 https://github.com/liuruijin17/LSTR 【LSTR算法介绍】 LSTR车道线检测算法是一种用于识别和定位车道线的计算机视觉算法。它基于图像处理和机器学习的技术,通过对道路图像进行分析和处理,提取出车道线的位置和方向等信息。 LSTR车道线…

Qt之使用Qt内置图标

一效果 二.原理 Qt内置图标封装在QStyle中,共七十多个图标,可以直接拿来用,能应付不少简单程序需求,不用自己去找图标并添加到资源文件了。 下面是内置图标的枚举定义: enum StandardPixmap {SP_TitleBarMenuButton,SP_TitleBarMinButton,SP_TitleBarMaxButton,SP_T…

error: failed to push some refs to....

使用 git push 时报错: AdministratorUSER-20231229RG MINGW64 ~/Desktop/工作/gitCode/answer-questions (master) $ git push -u origin master Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 8 threads Co…

PHP框架详解 - symfony框架

首先说一下为什么要写symfony框架,这个框架也属于PHP的一个框架,小编接触也是3年前,原因是小编接触Golang,发现symfony框架有PHP框架的东西也有Golang的东西,所以决定总结一下,有需要的同学可以参看小编的G…