Java集合:HashMap

Hashmap是一个存储key-value的映射表。

优点:

  • 索引数据快,查找一个数据对的时间复杂度是O(1)
  • 增加、删除一个数据的时间复杂度是O(1)
  • key不能重复,可以存储一个null值

存储:

  • 通过key的hashcode值存储在指定数组下标中
  • 用链表存储hashcode值一样,都是key不一样的数据,链表长度大于8时转换为红黑树(为了提高查询效率)

HashMap的内部结构

Hashmap封装了一个Node数组进行存储key-value的键值对,常用的get和put等都是对这个Node数组进行操作。

Node有四个属性:key、value、hash、next

  • hash:32位的整数,通过key的hashcode计算出来,hash&(数组长度-1) = 元素在数组的下标
  • next:指向Node节点的指针,不同的key计算出来的hash值可能是一样的,如果要存储的下标位置已经有值了,用链表将元素连起来

初始化HashMap:一开始HashMap内部是一个空的Node数组,插入数据后才会被创建

HashMap的常用操作

HashMap一开始的Node数组是空的,在第一次put元素后会默认创建一个长度为n = 16的数组

put一个key-value元素进入map中

计算key的hashcode值算出hash,得出index=hash&(长度-1),将元素存在数组[index]的位置。

有两种情况:

  • index这个位置已经有key了,比如当数组的长度是16时,33&(16-1) = 1. ,  1 & (16 - 1) = 1 ; key值不同,但是index一样。

    这里就用到了Node的next属性,让数组index下标所在的(最后一个)元素的next指向插入的元素,

  • 可以直接将元素存入数组中

通过key从map中get一个元素

计算key的hashcode值算出hash,得出index=hash&(长度-1)

有两种情况:

  • 如果数组[index]的值为null,就说明不存在这个元素
  • 不为null,还得比较key值,通过遍历链表(如果有的话),一个个比较key值,返回key相同的元素,或null

HashMap的优化操作

  • 数组长度n永远是2的幂:hash&(n-1)是元素在数组的下标,(2的幂-1)的二进制会是一连串的1,然后与hash值进行与运算
    • 与运算之后的结果永远不会超过数组的界限
    • 充分的利用了hash值二进制
  • 负载因子:hashmap设置了一个0.75的阈值,也就是数组中的元素数量大于数组长度的0.75时,进行数组扩容,扩展成原来的两倍
    • 当数组长度不够时,会出现很多的hash冲突,就是链表很长,检索效率慢,扩容后通过hash&(n-1)会让很长的链表散开
  • 链表转换成红黑树:链表长度大于8,但是数组元素数量没达到阈值,会选择将链表转换为红黑树,提高查询效率
    • 要求数组长度已经大于64,避免数组扩容和链表转红黑树的冲突
  • hash值的计算:hash值的前16位与key的hashcode一样,后16位由hashcode的前16位与后16位异或运算得到
    • 充分利用hashcode的值,增加随机性,减少hash冲突
posted @ 2021-09-19 14:15  划水的鱼dm  阅读(218)  评论(0编辑  收藏  举报