补充树相关的知识过程中,学习到红黑树,并查了一些红黑树的应用,
发现Java提供的数据工具包:HashMap中使用了红黑树,
之前在应对知识考核时也看了HashMap的相关数据组成,
但是,没有详细分析数据之间是如何转换存储结构的,
现在,正好借着学习树以及应用的机会,根据HashMap源码,
详细研究了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对应的形式。
使用HashMap存储数据,暴露给用户的方法为put,源码如下图所示,
由源码可知,put方法中,调用了putVal方法,这个方法才是实际的存储数据和数据结构转换的方法。
位置:java.util.HashMap#put
既然putVal才是最终的奥义,
那么继续看看这个方法的真实面目,如下图所示,
新增数据,
我已经将数据的类型和数据结构的变化在图中标出,
各位习者耐心看下,设计非常巧妙,
Node<>[]即数组;
p.next即链表,
treeifyBin即红黑树。
位置:java.util.HashMap#putVal
HashMap的Node有两种功能,
(1)直接存储kv;
(2)转换为单向链表;
源码如下图所示,有源码可知,属性key、value即可直接存储kv;
属性next即单向链表结构,使用链表存储数据。
前面的Node用于存储kv或者单向链表,
那么,红黑树则使用TreeNode存储数据,
属性,parent连接父节点,left和right是该节点的左右节点,prev前驱节点,删除时断开与next的连接,
red用于标识当前节点的特性:红或黑。
位置:java.util.HashMap.TreeNode
树化的方法为treeifyBin,即构建树化容器,
源码如下图所示,
有源码可知,首先构建TreeNode,然后通过treeify构建红黑树,
是的,核心是treeify方法。
位置:java.util.HashMap#treeifyBin
构建红黑树:
源码如下图所示。
位置:java.util.HashMap.TreeNode#treeify
(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。