关于HashMap的学习记录

目录

1.说说你对hash算法的理解。追问:hash算法任意长度的输入 转化为了 固定长度的输出,会不会有问题呢?追问:hash冲突能避免么?

2.你认为好的hash算法,应该考虑点有哪些呢?

3.HashMap中存储数据的结构是什么样的呢?

4.创建HashMap时,不指定散列表数组长度,初始长度是多少呢?追问:散列表是new HashMap() 时创建的么?

5.默认负载因子是多少呢,并且这个负载因子有什么作用?

6.链表转化为红黑树,需要达到什么条件呢?

7.Node对象内部的hash字段,这个hash值是key对象的hashcode()返回值么?追问:这个hash值是怎么得到呢?追问:hash字段为什么采用高低位异或?

8.HashMap put 写数据的具体流程,尽可能的详细点!

9.红黑树的写入操作,是怎么找到父节点的,找父节点流程?

10.TreeNode数据结构,简单说下。

11.红黑树的原则有哪些呢?

12.JDK8 hashmap为什么引入红黑树?解决什么问题?追问:为什么hash冲突后性能变低了?

13.hashmap 什么情况下会触发扩容呢?追问:触发扩容后,会扩容多大呢?算法是什么?追问:为什么采用位移运算,不是直接*2?

14.hashmap扩容后,老表的数据怎么迁移到扩容后的表的呢?

15.hashmap扩容后,迁移数据发现该slot是颗红黑树,怎么处理呢?

16.为什么hashmap大小要为2的幂次方数


1.说说你对hash算法的理解。追问:hash算法任意长度的输入 转化为了 固定长度的输出,会不会有问题呢?追问:hash冲突能避免么?

hash算法基本概念就是将任意长度的输入,映射转换为固定长度的输出。会。hash冲突只能尽量避免。


2.你认为好的hash算法,应该考虑点有哪些呢?

1.不可逆。得到的hash值不能逆推得到原文

2.尽可能分散,分布均匀

3.两个输入,只要有一点不同,得到的hash值也不同

4.效率高,要做到长文本也要快速高效输出hash值


3.HashMap中存储数据的结构是什么样的呢?

JDK7 以前是 数组 + 链表。 JDK8 是 数组 + 链表 + 红黑树。

JDK8 每个数据单元都是一个Node结构,其中node结构包括 key,value,hash,next四个字段。next 类型为node,用于hash冲突形成链表的时候存放下一个node


4.创建HashMap时,不指定散列表数组长度,初始长度是多少呢?追问:散列表是new HashMap() 时创建的么?

初始长度:16。散列表采用的是懒加载机制,构造函数中没有传参的时候,只有第一次put值的时候才进行初始化。


5.默认负载因子是多少呢,并且这个负载因子有什么作用?

0.75f。用于计算扩容。例如默认情况下扩容边界为:16 * 0.75 = 12


6.链表转化为红黑树,需要达到什么条件呢?

1. 桶位hash冲突形成的链表长度大于8

2.散列表table长度大于64


7.Node对象内部的hash字段,这个hash值是key对象的hashcode()返回值么?追问:这个hash值是怎么得到呢?追问:hash字段为什么采用高低位异或?

不是,是key.hashCode()的高低位异或得到。目的是为了让高位参与运算,避免高位浪费

public final int hashCode() {
     return Objects.hashCode(key) ^ Objects.hashCode(value);
}


8.HashMap put 写数据的具体流程,尽可能的详细点!

key经过寻址运算之后得到桶位的位置后,

1.桶位为空,直接放进去

2.桶位不为空,如果没有hash冲突,替换值

3.桶位不为空,hash冲突,链表的情况,遍历链表,遇到相同的就替换,没有则放在链表尾部(尾插法)

4.桶位不为空,hash冲突,红黑树 // todo

put完成之后,如果元素个数大于扩容阈值时进行扩容


9.红黑树的写入操作,是怎么找到父节点的,找父节点流程?


10.TreeNode数据结构,简单说下。


11.红黑树的原则有哪些呢?


12.JDK8 hashmap为什么引入红黑树?解决什么问题?追问:为什么hash冲突后性能变低了?

当散列表hash冲突形成链表十分严重,这时候的查找效率又会大大降低,在时间与空间的权衡之下,红黑树已空间换时间的方式来提高查找效率。

理想情况下散列表查找效率为O(1) 链表 O(n) 红黑树O(logN)


13.hashmap 什么情况下会触发扩容呢?追问:触发扩容后,会扩容多大呢?算法是什么?追问:为什么采用位移运算,不是直接*2?

例如 默认情况下,当元素个数大于 16 * 0.75 = 12 之后会进行扩容。

每次扩容都是之前的两倍,newCap = oldCap << 1。表大小左移一位

因为散列表大小为2的幂次方数,而位移运算高效快速,计算机底层没有乘法操作


14.hashmap扩容后,老表的数据怎么迁移到扩容后的表的呢?

1.桶位null

2.桶位只有一个元素,将元素key的hash值与扩容后的大小-1,e.hash & (newCap - 1)

3.桶位为链表,会拆分成高低位链,低位链的数据跟老表中的位置一样,高位链的位置需要加上老表的长度

    假如原链表上的2个二进制数分别为:....1 0011,....0 0011,原表大小16,二进制为...1 0000,

    ....1 0011 & ....1 0000 = ....1 0000 高位结果为1.移入高位链中,即该元素在新表的位置在老表的位置 + 老表的长度

    ....0 0011 & ....1 0000 = ....0 0000 高位结果为0.移入低位链中,即该元素在新表的位置与在老表位置一致

4.桶位为红黑树


15.hashmap扩容后,迁移数据发现该slot是颗红黑树,怎么处理呢?

 

16.为什么hashmap大小要为2的幂次方数

一个key的hashCode是一个int整数,而int在内存中是以二进制数存储,位运算比运算符运算更高效。当长度为2的幂次方数时,hash & (length -1) = hash % length


https://space.bilibili.com/457326371?spm_id_from=333.788.b_765f7570696e666f.2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值