面试回答之Hashmap

本文深入探讨HashMap的存储原理,从JDK1.8的Entry和Node结构,到涉及的数据结构如数组、链表、红黑树。详细阐述了哈希算法、负载因子、路由寻址公式及HashMap的重要方法,包括put、resize等,揭示HashMap何时扩容的机制。
摘要由CSDN通过智能技术生成

1、hashmap存储原理

jdk1.8 对 hashmap 底层的实现进行了优化,例如引入了红黑树的数据结构和扩容的优化。

HashMap的底层是:数组+红黑树+链表
在这里插入图片描述
在 JDK1.7 中HashMap 的数据是存储在 类型为 Entry 的一个 table 数组 中的,在JDK1.8 中使用的是 Node,Node 是 Map.Entry 的一个子类。

1)Entry

Entry 是 HashMap 的一个静态内部类:Entry 中封装了 key 和 value
在这里插入图片描述
在这里插入图片描述
key 和 Value 是已知的,next 指的是指向下一个链表结点,那 hash 是什么呢?
Node.hash 是指 key 对应的 hash 值。

2)Node

Node是Entry的一个子类:
在这里插入图片描述
Node 类中的这个 hash,是 key 的 hash 值经过一次扰动后得到的 哈希值。

Hash 会发生碰撞,有相同 key 的会放置到链表中。Hash 碰撞带来的问题:相同 key 的链表的长度会很长,但是 get(key) 请求,在找节点时,时间复杂度会很大。

2、HashMap涉及到的数据结构

散列就是来整合数组和链表的优势和劣势的,在散列表的数组中保存的数据是链表。

1)数组

数组的缺点:不能扩展空间
数组的优点:根据index查找的快

2)链表

链表的缺点:只保留head节点,但是想要访问最后一个元素,只能从头元素开始遍历
链表的优点:链表可以扩展空间

3)平衡二叉树

它是一棵空树,或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

4)红黑树

红黑树的提出,是为了解决相同 key 的链表的长度会很长,从而带来的链化问题,提高查找效率。

一种含有红黑结点,并且能自平衡的二叉查找树。

它具备的性质:
1)每个结点要么是黑色,要么是红色;
2)根节点是黑色;
3)每个叶子结点是黑色;
4)每个红色结点的两个子结点一定都是黑色,红色结点不能和红色结点直接相连;
5)任意一个结点到叶子结点的路径都包含数量相同的黑结点。

3、hash算法

哈希算法是一类算法的统称,也叫作散列算法。

f(data)=key;
  • 输出数据长度固定:输入任意长度的 data 数据,经过哈希算法处理后输出一个定长的数据 key,该输出就是散列值(把任意长度的输入,通过Hash算法变成固定长度的输出)。
  • 单向特征:无法由 key 逆推出 data,即哈希算法是一种单向密码机制,即它是一个从明文到密文的不可逆映射,只有加密过程而没有解密过程。
  • 常用的哈希算法:MD4、MD5、SHA-1

4、负载因子

比如我们存储70个元素,但我们可能为这70个元素申请了100个元素的空间,70/100=0.7,这个数字称为负载因子。

5、路由寻址公式

(table.length - 1) & node.hash()

假设 n=table.length
首先要明白 tab[(n-1) & hash] 中的 (n-1) & hash 即 路由寻址公式 的妙处:
(1)保证不会发生数组越界。数组的长度的二进制形式是 1000…000,那么 n-1 的二进制形式就是 0111…111,这个值和hash值进行与操作,结果一定不会比数组的长度值大,即不会发生数组越界。
(2)保证元素尽可能地均匀分布。假设此时

n=16;   //0x10000
n-1=15;   //0x1111

假设现在有两个元素要插入,一个哈希值是8,二进制为 1000; 一个哈希值是9,二进制为1001。

见 7 中的 hash() 函数,

假如table.length-1为15即0x1111,那么使参与“&”运算的不止是hashCode的低16位,使其也包含高位的值(hashCode的高16位 异或 hashCode的低16位,然后进行与运算)。

6、HashMap中较为重要的几个常量

1static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 ,即1左移4位,缺省table大小
2static final int MAXIMUM_CAPACITY = 1 << 30;  //table最大长度,即数组最大长度
3static final float DEFAULT_LOAD_FACTOR = 0.75f;  //缺省负载因子大小,0.75是科学家精确计算后的
4static final int TREEIFY_THRESHOLD = 8;  //树化阈值,当发生哈希碰撞后会形成链表,链表长度到8后,可能形成一个树了
5static final int UNTREEIFY_THRESHOLD = 6
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值