HashMap

哈希表:根据设定的哈希函数H(key)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表被称为哈希表。这一映射过程称为哈希表造表或散列,所得的存储位置称为哈希地址或散列地址。

一.哈希冲突

哈希冲突也叫哈希碰撞。当两个不同的元素通过哈希函数得出的实际地址相同时,就会发生哈希冲突。也就是说,当我们对某个元素进行哈希运算得到一个存储地址,然后要进行插入时,发现被其他元素占用了,就会发生哈希冲突。哈希冲突只可减少,不可避免。

哈希冲突的解决方案:

开放地址法,再散列函数法,链地址法。HashMap采用了链地址法,也就是数组加链表的方法。

1.开放地址法

开放地址法的关键特征在于输入的元素全部存放在哈希表中,位桶的实现不需要任何链表来实现,因此,哈希表的负载因子不会超过1。开放地址法的实现是在插入一个元素的时候,先通过哈希函数进行判断,若是发生哈希冲突,就以当前地址为基址,根据在寻址的方法(探查序列),去寻找下一个地址,若发生冲突,再去寻找,直到找到一个空得地址为止。

常用的探查序列的方法:

线性探查:特点:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

二次查找:特点:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

伪随机数序列:建立一个伪随机数发生器,生成一个伪随机序列。

2.再散列函数法

在使用哈希函数去散列一个输入时,输出是同一位置就再次散列,直至不发生冲突位置。

缺点:每次冲突都要重新散列,计算时间增加。

3.链地址法

HashMap,HashSet都是采用链地址法来解决哈希冲突的,在每个位桶实现的时候,采用链表(jdk1.8后采用链表+红黑树)的数据结构来存取发生哈希冲突的输入域的关键字(也就是被哈希函数映射到同一个位桶上的关键字)。其基本思路是:将所有具有相同哈希地址而不同关键字的数据元素连接到同一个单链表中。如果选定的哈希表长度为m,则可将哈希表定义为一个有m个头指针组成的指针数组T[0..m-1],所有哈希地址为i的数据元素,均以节点的形式插入到T[i]为头指针的单链表中。并且新的元素插入到链表的前端,因为方便且最有可能不久又被访问。

在使用链地址法进行删除操作时,如果想使用链表来实现位桶,那么这个链表必须是双向链表。

与开放地址法相比,链地址法具有如下优点:

(1)链地址法处理冲突简单,且无堆积现象,因此平均查找长度较短。

(2)由于链地址法各链表上的节点空间是动态申请的,所以它更适合于造表前无法确定表长的情况。

(3)开放地址法为减少冲突,要求负载因子α较小,所以当结点规模较大时会浪费很多空间。而链地址法可取α>=1,且结点较大时,链地址法中增加的指针域可忽略不计,因此节省空间。

(4)再用链地址法构造的散列表中,删除结点的操作易于实现,只要简单的删去链表上相应的节点即可。

链地址法的缺点:

指针需要额外的空间,因此当规模较小时,开放地址法较为节省空间,而若将节省的指针空间用来扩大散列表的规模,可使负载因子变小,这又减少了开放地址法中的冲突,从而提高平均查找速度。

二.HashMap底层

HashMap在底层将key-value当成一个整体来进行处理,这个整体就是一个Entry对象。HashMap底层采用一个Entry[]数组来保存所有键值对,当需要存储一个Entry对象时,会根据Hash算法来决定存储位置,当需要取出一个Entry时,也会根据Hash算法找到其存储位置,直接取出该Entry。

三.HashMap基础

1.创建HashMap时,有一个默认的负载因子(load factor),其默认值是0.75,增大负载因子可以减少hash表(就是Entry数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的操作(HashMap中的get()和put()方法都要用到查询操作),减少负载因子会提高数据查询的性能,但会增加Hash表所占用的内存空间。

2.

Entry数组长度:capacity(默认值为16)

Entry极限容量:capacity*load factor

当链表中元素个数超过默认值8,且数组长度超过64时,链表会转换为红黑树。若链表中元素的个数超过8个,但数组没超过64,则进行数组扩容。

如果开始就知道HashMap会保存多个键值对,可以在创建时就使用较大的初始化容量,当HashMap中Entry的数量超过极限容量时,HashMap就无需调用resize()方法重新分配table数组,从而保证较好的性能,当容量超出极限容量后,resize后的容量是容量的二倍。当然,开始就将初始容量设置太高可能会浪费空间,因此设置初始容量时要小心。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值