在之前有一篇博客介绍了HashMap,数据结构之Hash表(哈希表)
现在对之前的内容做一个补充。
说HashMap之前,看下数组:
数组的优点在于查找速度快,每个区域都是紧挨着的,并且有下标,可以根据下标快速找到要查找的元素。
缺点:增删麻烦,如果在第二个元素后面再添加个元素的话,那么就需要重新建一个数组,填入对应的信息。
链表:每个内存除了存放自身的元素外,还保留下个内存区域的地址,
优点:插入新元素方便,只需要将指针指向新元素,新元素指向原来的下一个指针即可。
缺点:查找速度慢。链表不像数组那样有下标,链表查找元素只能从head结点开始,一个一个向下找。
而散列表则是综合了两者优点于一身的结构:
上面是数组,数组每个区域内是链表。
说到散列表,就应当说哈希,没有哈希,散列表就无法寻址找数据,
哈希
哈希:Hash也称散列、哈希,对应的英文都是Hash,基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出,这个映射的规则就是对应的Hash算法,而原始数据映射后的二进制串就是哈希值。
Hash特点:
1、hash值不可以反向推导出原始的数据
2、输入的数据的微小变化会得到完全不同的hash值,相同的数据可以得到相同的值。
3、哈希算法的执行效率要高效
4、hash算法的冲突概率要小
hash原理是将输入空间的值映射成hash空间内,但是hash空间的大小是要小于输入空间的大小的,所以说是存在不同的输入值被映射成相同输出的情况。
底层存储结构
hashmap的默认长度是16。如果要改变长度,也应当是2的次方,也就是16,32这些。当每个链表的长度超过8,达到9的时候,并且所有的元素超过64个,链表就变为红黑树。
其实hashmap就是数组+链表+红黑树组成的。
put数据原理分析
map.put(“别云”,“无用”);key就是别云,而无用就是value。
接下来获取key的hash值,也就是别云的hash值。
经过hash值扰动函数,使此hash值更散列。
构造出对象;
根据路由算法,找出对象应在数组中存放的位置。
路由寻址:
(table.length-1) & node.hash;table.length就是该hashmap的长度,node.hash就是获取字符串“别云”的hash值,将两者相与,得到要存放在数组中的位置。
hash碰撞
假如刚才的map.put(“别云”,“无用”);经过路由算法,最后存放在数组的第三个位置,而map.put(“恍惚之境”,“启明星的指引”);也是存放到第三个位置。两者都是存放到一个位置,这个就是hash碰撞。只需要将原结点指向新节点即可,形成个新链表。
链化
如果多次执行put操作,其中有多个元素都是放在位置3上,如果存放的多了,位置三上的链表的长度就会很长,此时进行查询操作,时间复杂度就会由O(1)变为O(N)。这就是链化。
jdk1.8引入红黑树
jdk1.8引入红黑树就是为了解决上面的链化问题,当结点较多的时候,链表转化为红黑树提高查询效率,红黑树是一种平衡二叉查找树,关于红黑树,这两天就会写到。
HashMap扩容
假如一个haspMap大小为16,每个块有四个结点。假如扩容之后,大小为32,那么每块则只有两个结点。这就是用空间换取时间的做法。
接下来就是对HashMap源码的介绍展示
来源:CSDN
作者:夜笙孤酒
链接:https://blog.csdn.net/weixin_44298615/article/details/104137055