数据结构——4、散列表

1.1.1 *散列表*

散列表,即哈希表,这种数据结构提供了key和value的映射关系,在jdk中也叫做entry,只要给出一个key,就能查找出相应的value,查找的时间复杂度接近于O(1)

散列表本质上也是一个数组,数组是根据角标来查找元素的,散列表是根据key来查找元素的,且key以string类型为主

1.1.1.1 *哈希函数*

将key与数组下标进行转换的中转站就是哈希函数

img

如何进行中转:

无论对象自身是什么类型,它们的hashCode都是一个整型变量,将整形变量转换为数组下标就很容易了,按照数组长度进行取模运算

index=HashCode(key)%Array.length

jdk中的哈希函数不是直接进行取模运算,而是利用了位运算的方式来优化性能

1.1.1.2 *哈希冲突*

在散列表中插入新的entry,步骤:

1、 先要通过哈希函数,将key转化成数组下标

2、 如果数组下标没有这个元素,就将entry填充到这个下标所在位置;

如果数组下标有这个元素,就将entry追加到链尾

不同的key通过哈希函数获得的下标可能是相同的,即产生了哈希冲突,哈希冲突的解决方法包括两种:开放寻址法;链表法;

1.1.1.2.1 *开放寻址法*

当一个key通过哈希函数获得的数组下标已经被占用,就顺序查找下一个空挡位置,直到找到没有被占用的位置,

这种寻址方式是最简单的一种,可以有多种寻址方式

1.1.1.2.2 *链表法*

当一个key通过哈希函数获得的数组下标已经被占用,就直接追加到相应的链表的链尾即可

这里HashMap数组中的每一个元素不仅是一个entry对象,还是一个链表的头节点

1.1.1.3 *扩容*

数组的扩容,是直接在原来容量的基础上,扩大一倍,

散列表是基于数组实现的,那么也涉及到扩容问题,当拥挤在相同的数组下标位置,形成很长的链表,就会对后续插入和查询操作的性能有很大影响

影响散列表扩容的因素有两个:

1、 capacity:即hashmap的当前长度;

2、 loadFactor:即hashmap的负载因子,默认值是0.75f

衡量hashmap需要扩容的条件是:

HashMap.Size>=Capacity*LoadFactor

HashMap的扩容操作不是简单的将长度扩大,而是包括两个操作:

1、 扩容:创建一个新的entry空数组,长度是原来数组的2倍;

2、 rehashing:即重新hash,遍历原entry数组,将所有的entry重新hash到新数组中

为什么要重新进行hash?因为长度扩大之后,hash的规则也随之改变了,为了将元素尽可能均匀的分配

JDK1.8版本的hashmap和以前有很大的不同:

当多个entry被hash到同一个数组下标位置时,为了提升插入和查找的效率,hashmap会将entry的链表转换为红黑树结构

posted on 2021-09-27 10:15  夜萤火虫和你  阅读(149)  评论(0编辑  收藏  举报

导航