散列表
概念:一种数据结构,将key映射到映射到表中一个位置以便快速访问记录,结合数组、链表优点,高效增删改
散列表通常使用一个数组来存储数据。数组的每个位置称为一个槽
当两个不同的键通过散列函数得到相同的槽位置时,就会发生冲突。解决冲突的常见方法有开放寻址法(如线性探测、二次探测、双重散列)和链地址法(将冲突的元素链接在一起)。
缺点:额外的策略来解决哈希冲突,为了减少冲突,散列表的数组大小通常要大于存储的数据量,这可能导致空间的浪费,散列函数的选择
哈希:就是将任意长度的输入,通过hash算法都可以得到固定长度的输出,从hash值不可以退出原始数据
HashMap原理
继承体系:
底层存储结构:
Node数组默认初始化长度为16(源码中定义的常量,1左移四位),当Node数组中所有元素个数超过64,并且链表长度大于8时,链表将变成红黑树
put原理
首先构造出Node节点,通过hash计算出key的的HashCode值,然后通过扰动函数使Hash值更散列得到最终Hash值,通过路由算法(表的长度-1&Hash值 )找到在Node数组中存放的位置
扰动函数的意义:让表的长度不是很高的情况下,让HashCode的高16位也进行到路由算法的计算中
表的长度一定是2的多少次方?
当数组长度是2的幂次方时,表长度减1之后是全1,然后和其他数做与运算可以快速算出存放的索引位置
为什么引入红黑树:自平衡的二叉搜索树,就是为了防止链化过长,导致取同一个Hash值的时候遍历时间过长,链化遍历复杂度为O(n),而于红黑树来说,它的时间复杂度是O(logN)
扩容原理
只有在第一次在HashMap里面插数据的时候才会初始化,延迟初始化
负载因子,就是当Node数组长度*负载因子时,会出发扩容
对于扩容时的流程中(扩容容量翻倍),只需要判断hash&oldcap==0?保留原位置:旧位置+旧容量