当前位置: 首页 > news >正文

源码硬讲HashMap结构及数据结构转换过程(图+文)

1 缘起

补充树相关的知识过程中,学习到红黑树,并查了一些红黑树的应用,
发现Java提供的数据工具包:HashMap中使用了红黑树,
之前在应对知识考核时也看了HashMap的相关数据组成,
但是,没有详细分析数据之间是如何转换存储结构的,
现在,正好借着学习树以及应用的机会,根据HashMap源码,
详细研究了HashMap的数据转换过程,
分享如下,
帮助读者轻松应对知识考核与交流。

2 分析

2.1 理论:回顾HashMap

HashMap是一个组合的数据结构。
根据自己动手丰衣足食的设计原则,当某种开发语言不支持更加高效的数据结构存储数据时,
开发者可根据实际需要,编写自己的数据结构,
这不,Java工具包开发者组合了数组、链表和红黑树,创造了HashMap,
集相对高效的CURD于一身。
老规矩,根据理论,
先看看HashMap的数据结构,如下图所示,
由图可知,HashMap默认的数组元素有16个,
数组中的元素存储情况:
(1)key没有Hash冲突,则按照kv形式存储,如key2对应的形式;
(2)key有Hash冲突且冲突的key个数小于7个,使用链表存储,如key1对应的形式;
(3)key有Hash冲突且冲突的key个数大于等于7个,使用红黑树存储,如key3对应的形式。

在这里插入图片描述

2.2 实践:新增数据

使用HashMap存储数据,暴露给用户的方法为put,源码如下图所示,
由源码可知,put方法中,调用了putVal方法,这个方法才是实际的存储数据和数据结构转换的方法。
位置:java.util.HashMap#put
在这里插入图片描述

既然putVal才是最终的奥义,
那么继续看看这个方法的真实面目,如下图所示,
新增数据,
我已经将数据的类型和数据结构的变化在图中标出,
各位习者耐心看下,设计非常巧妙,
Node<>[]即数组;
p.next即链表,
treeifyBin即红黑树。

位置:java.util.HashMap#putVal
在这里插入图片描述

2.3 Node

HashMap的Node有两种功能,
(1)直接存储kv;
(2)转换为单向链表;
源码如下图所示,有源码可知,属性key、value即可直接存储kv;
属性next即单向链表结构,使用链表存储数据。
在这里插入图片描述

2.4 TreeNode

前面的Node用于存储kv或者单向链表,
那么,红黑树则使用TreeNode存储数据,
属性,parent连接父节点,left和right是该节点的左右节点,prev前驱节点,删除时断开与next的连接,
red用于标识当前节点的特性:红或黑。
位置:java.util.HashMap.TreeNode
在这里插入图片描述

2.5 树化:构建红黑树

树化的方法为treeifyBin,即构建树化容器,
源码如下图所示,
有源码可知,首先构建TreeNode,然后通过treeify构建红黑树,
是的,核心是treeify方法。
位置:java.util.HashMap#treeifyBin
在这里插入图片描述
构建红黑树:
源码如下图所示。
位置:java.util.HashMap.TreeNode#treeify
在这里插入图片描述

3 小结

(1)HashMap由3种数据结构构成:数组、单向链表和红黑树;
(2)数据结构转换过程:
(2.1)key没有Hash冲突,则按照kv形式存储,如key2对应的形式;
(2.2)key有Hash冲突且冲突的key个数小于7个,使用链表存储,如key1对应的形式;
(2.3)key有Hash冲突且冲突的key个数大于等于7个,使用红黑树存储,如key3对应的形式。
(3)红黑树转换时,先构建TreeNode数组,然后转换为红黑树,红黑树转换的核心方法为:java.util.HashMap.TreeNode#treeify。

相关文章:

  • 优化程序性能
  • 【Java】【集合】集合框架Collection
  • 这些年,我与Google不得不说的那些事儿
  • Opencv——图像模板匹配
  • 【秋招面经】之神策数据
  • Spring 有几种事务隔离级别?
  • 若依(RuoYi )权限管理设计
  • 【024】 快速上手mongoose web服务器
  • DevOps自动化测试的原则和实践
  • `SpringBoot`+`axios`结合发送`ajax`请求
  • 电子元器件产业发展遇新机,SRM供应商协同管理系统实现与供应商的敏捷协同
  • C#基础入门教程-基本语法
  • TensorRT安装记录(8.2.5)
  • C++ 池式组件 线程池 内存池 异步请求池 MySQL连接池
  • SwiftUI 动态岛开发教程之 05 Dynamic Island 和 Live Activity 无需太多代码即可为用户提供大量信息
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • [译]Python中的类属性与实例属性的区别
  • 【Leetcode】104. 二叉树的最大深度
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 77. Combinations
  • JS变量作用域
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Otto开发初探——微服务依赖管理新利器
  • php中curl和soap方式请求服务超时问题
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • vue-router 实现分析
  • 开源SQL-on-Hadoop系统一览
  • 如何编写一个可升级的智能合约
  • 推荐一个React的管理后台框架
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • # .NET Framework中使用命名管道进行进程间通信
  • #if 1...#endif
  • #QT(智能家居界面-界面切换)
  • #前后端分离# 头条发布系统
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (zt)最盛行的警世狂言(爆笑)
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (转)Windows2003安全设置/维护
  • (转)编辑寄语:因为爱心,所以美丽
  • (转载)OpenStack Hacker养成指南
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .gitignore文件—git忽略文件
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET delegate 委托 、 Event 事件,接口回调
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .net mvc 获取url中controller和action
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .net程序集学习心得
  • .net快速开发框架源码分享