HashMap学习(抄袭)记录
HashMap:
基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键
初始容量16, 加载因子0.75
查询的时间复杂度
数组: O(1)
链表: O(n)
红黑树: O(logn)
JDK 1.7
数据结构: 数组 + 链表
hash冲突后, 就都会形成链表, 是不想出现的结果, 数组就会扩容, 尽量避免hash冲突
JDK 1.8
数据结构: 数组 + 链表 + 红黑树
JDK 1.7基础上, 链表长度过长, 会导致查询效率常数阶O(1)变成线程阶O(n) , 为了提高查询效率 , 引入红黑树
红黑树(百度百科):
红黑树是一种平衡二叉查找树 , 是计算机科学中用到的一种数据结构, 典型的用途是实现关联数组
一张红黑树的图片
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3.所有叶子都是黑色。(叶子是NUIL节点)
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5… 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
HashMap存值过程
1. 根据key计算一个hash值
2. 在put的时候判断数组是否存在, 如果不存在创建一个默认长度为16的数组
3. 根据key的hash值与数组中的最大索引值进行与(&)运算得到索引位置 , 确定node在数组中的位置
4. 判断该位置是否有元素, 如果没有元素直接放进去, 如果有元素, 判断key是否相同, 如果相同 , 把原来的node赋值给一个变量
5. 再去判断该位置是红黑树还是链表
6. 如果是红黑树, 以红黑树的形式将node放在树上, 如果是链表放在链表的最后位置
放完之后判断链表长度 , 如果链表长度大于8则要判断是否变成红黑树
摘要: 当数组容量小于64时 , 只会进行扩容, 大于64转成红黑树.
7. 返回被覆盖的值
8. 判断整个数组是否需要扩容
面试题
1. HashMap在JDK1.7和JDK1.8的区别?
1.7中的数据结构是数组 + 链表, 1.8之后是数组+ 链表 + 红黑树
2. HashMap如何确定键值对的位置? 如何解决hash冲突
根据key的hash值与数组中的最大索引值进行与(&)运算得到索引位确定键值对位置 , 如果key的hash值相同, key值也相同 , 替换当前value值, 如果key的hash值相同, key值不同, 行程一个单向链表 , 然后元素以Entry<V, V>的形式存放在链表中 , 以此解决hash冲突
3. 扩容为什么每次都是2的次幂
为了尽量减少hash冲突
4. HashMap和HashTable、ConcurrentHashMap的区别
HashMap线程不安全, HashTable, ConcurrentHashMap线程安全, HashTable方法都是用synchronized修饰的同步代码块 , 由于并发情况下效率过低 , 所有就有了ConcurrentHashMap的存在 , ConcurrentHashMap在JDK1.7的时候使用的分段锁, 1.8使用CAS解决线程安全问题和高并发响应速度
5. 为什么要在put的时候创建数组
数组在内存中占用的一段连续的内存空间, 占用内存较多, 所以创建的map不使用也创建数组的话, 就会浪费内存.
6. HashMap什么时候会变成红黑树? 什么时候由红黑树变成链表?
在数组长度到达64 , 并且链表长度到达8个时候由链表变成红黑树 , 当元素数量小于等于6的时候由红黑树转成链表.
7. 链表的时间复杂度和红黑树的时间复杂度分别是多少?
链表O(n), 红黑树O(logn), 红黑树优于链表
8. 为什么不直接使用红黑树而使用链表?
因为树节点占用的存储空间是普通链表的两倍, 所以当节点足够多的时候才会使用红黑树 .
内容来源于网络 , 不足的地方大家多多指出.
我是大自然的搬运工
总结大部分来自 bilibili: https://www.bilibili.com/video/BV1PC4y1Y7q8?from=search&seid=9319419595277626165