HashMap底层数据结构及其增put删remove查get方法的代码实现原理

简介: HashMap 是基于数组 + 链表 + 红黑树实现的高效键值对存储结构。默认初始容量为16,负载因子为0.75。当存储元素超过容量 * 负载因子时,会进行扩容。HashMap 使用哈希算法计算键的索引位置,通过链表或红黑树解决哈希冲突,确保高效存取。插入、获取和删除操作的时间复杂度接近 O(1)。

PS:由于文档是我在本地编写好之后再复制过来的,有些文本格式没能完整的体现,故提供下述图片,供大家阅览,以便有更好的阅读体验:
image.png

1.HashMap底层数据结构是数组+链表(jdk1.7头插法<扩容时链表逆序可能会导致环形链表的问题出现> jdk1.8尾插法)+红黑树(jdk1.8).
2.HashMap中数组的容量默认为16,负载因子默认为0.75,当数组的0-15个下标里有16×0.75=12个被使用时,且HashMap中存储的元素总个数大于64时,则发生扩容操作,数组的容量扩大为原来的2n.
3.负载因子代表数组中存储数据密度的大小:负载因子越大,数组单位容量内存储的数据越多,不同元素之间(key不同,但计算得到的数组下标相同)越容易发生碰撞(哈希碰撞);反之,则单位容量内存储的数据越少,越不易发生碰撞.
4.put(key,value)时的处理逻辑:
(1)hash(key) = (key==NULL)?0:(h=key.hashCode())^(h>>>16),即取key的原始哈希码的高低16位进行异或位运算,计算出一个经高低位混合后高低位分布更加均匀的新哈希码,再用该新哈希码和数组容量减一做与位运算(hash(key)&(2^n-1))得出要存放的数组下标[当HashMap的容量是2的n次幂时,(2^n-1)的二进制就是11111*111全1的形式,这样与hash(key)进行与的位运算时,能够充分的散列,使得添加的元素均匀分布到HashMap的每个位置上,减少hash碰撞],可以一定程度降低根据不同元素计算得出相同数组下标(哈希碰撞)的概率;
(2)得出的数组下标里已经存放有数据元素,则根据key的值遍历比较该下标下的链表或红黑树,如果遇到相同key,则更新key对应的value值后返回(return);若遍历链表后未遇到相同的key,则在链表(jdk1.7头部 jdk1.8尾部)或红黑树合适位置(可能触发红黑树的左旋右旋或颜色改变),插入新的(key,value)键值对元素(插入值时统计存储的总元素个数的变量值会加一) ;
(3)某链表插入新的键值对后,可能导致该链表的长度大于等于8,若此时数组存储的总元素个数大于等于64,则将链表转为红黑树(保证最好最坏情况下时间复杂度为以2为底总元素个数n的对数级别,以提高增删查处理性能);
(4)链表插入新值后,也可能会触发数组扩容操作
5.get(key)时的处理逻辑:同put(key,value)的步骤(1),会根据key值计算得出数组下标,然后用key值遍历比较该数组下标下的链表或或红黑树,找到相同key对应的value值并返回,否则,返回null;
6.remove(key)时的处理逻辑:同get(key)和put(key,value)的步骤(1),会先根据key找到要删除元素所在位置,然后进行删除操作;

目录
相关文章
|
4月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
101 2
|
3月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
92 1
|
4月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
42 1
|
4月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
83 5
|
4月前
|
算法 索引
让星星⭐月亮告诉你,HashMap的resize()即扩容方法源码解读(已重新完善,如有不足之处,欢迎指正~)
`HashMap`的`resize()`方法主要用于数组扩容,包括初始化或加倍数组容量。该方法首先计算新的数组容量和扩容阈值,然后创建新数组。接着,旧数组中的数据根据`(e.hash & oldCap)`是否等于0被重新分配到新数组中,分为低位区和高位区两个链表,确保数据迁移时的正确性和高效性。
85 3
|
4月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
70 2
|
4月前
|
机器学习/深度学习 算法
让星星⭐月亮告诉你,HashMap之tableSizeFor(int cap)方法原理详解(分2的n次幂和非2的n次幂两种情况讨论)
`HashMap` 的 `tableSizeFor(int cap)` 方法用于计算一个大于或等于给定容量 `cap` 的最小的 2 的幂次方值。该方法通过一系列的无符号右移和按位或运算,逐步将二进制数的高位全部置为 1,最后加 1 得到所需的 2 的幂次方值。具体步骤包括: 1. 将 `cap` 减 1,确保已经是 2 的幂次方的值直接返回。 2. 通过多次无符号右移和按位或运算,将最高位 1 后面的所有位都置为 1。 3. 最终加 1,确保返回值为 2 的幂次方。 该方法保证了 `HashMap` 的数组容量始终是 2 的幂次方,从而优化了哈希表的性能。
45 1
|
3月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
315 9
|
3月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
50 1
|
30天前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
138 77

热门文章

最新文章