JAVA HashMap知识点梳理

Hash

Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。根据散列值作为地址存放数据,这种转换是一种压缩映射,简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。查找关键字数据(如K)的时候,若结构中存在和关键字相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。我们称这个对应关系f为散列函数(Hash function),按这个事件建立的表为散列表。

HashMap原理图

在这里插入图片描述

  • JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突;
  • JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间;

首先有一个每个元素都是链表(可能表述不准确)的数组,当添加一个元素(key-value)时,就首先计算元素key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素已经被放在数组同一位置了,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,但是形成了链表,同一各链表上的Hash值是相同的,所以说数组存放的是链表。而当链表长度太长时,链表就转换为红黑树,这样大大提高了查找的效率。

扩容

当链表数组的容量超过初始容量的0.75时,再散列将链表数组扩大2倍,把原链表数组的搬移到新的数组中。

get()

get(key)方法时获取key的hash值,计算hash&(n-1)得到在链表数组中的位置first=tab[hash&(n-1)],先判断first的key是否与参数key相等,不等就遍历后面的链表找到相同的key值返回对应的Value值即可。

put() 与 hash冲突
  • 判断键值对数组tab[]是否为空或为null,否则以默认大小resize();
  • 根据键值key计算hash值得到插入的数组索引i,如果tab[i]==null,直接新建节点添加,否则转入3;
  • 判断当前数组中处理hash冲突的方式为链表还是红黑树(check第一个节点类型即可),分别处理;

对不同的关键字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),这种现象称hash冲突。即:key1通过f(key1)得到散列地址去存储key1,同理,key2发现自己对应的散列地址已经被key1占据了。

JDK1.8使用红黑树的改进

在Java jdk8中对HashMap的源码进行了优化,在jdk7中,HashMap处理“碰撞”的时候,都是采用链表来存;
在jdk8中,HashMap处理“碰撞”增加了红黑树这种数据结构,当碰撞结点较少时,采用链表存储,当较大时(>8个),采用红黑树存储(有一个阀值控制,大于阀值(8个),将链表存储转换成红黑树存储);
在这里插入图片描述

补充:Hash冲突解决方案
  • 开放寻址法
    比如说,我们的关键字集合为{12,67,56,16,25,37,22,29,15,47,48,34},表长为12。 我们用散列函数f(key) = key mod l2,当计算前S个数{12,67,56,16,25}时,都是没有冲突的散列地址,直接存入:

在这里插入图片描述计算key = 37时,发现f(37) = 1,此时就与25所在的位置冲突。于是我们应用上面的公式f(37) = (f(37)+1) mod 12 = 2。于是将37存入下标为2的位置:
在这里插入图片描述
即当冲突发生时,使用某种探测技术(线性探测法、二次探测法(解决线性探测的堆积问题)、随机探测法(和二次探测原理一致,不一样的是:二次探测以定值跳跃,而随机探测的散列地址跳跃长度是不定值))在散列表中形成一个探测序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止插入即可。

  • 再哈希
    再哈希法又叫双哈希法,有多个不同的Hash函数,当发生冲突时,使用第二个,第三个,….,等哈希函数去计算地址,直到无冲突。虽然不易发生聚集,但是增加了计算时间。
  • 链地址法(Java hashmap就是这么做的)
  • 建立一个公共溢出区
    将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值