前言
提示:对于初始的哈希图朋友,不建议直接固执。建议您查看以下视频教程,然后回顾好。(如果您不了解,请重复查看。
lollow(哈希)表
核心理论:
哈希也称为散射和哈希,相应的英语是哈希。基本原理是通过哈希算法将任何长度的输入更改为固定长度的输出的输入。该映射的规则是相应的哈希算法,,,,算法。原始数据映射之后的二进制字符串是哈希值。
哈希特征:
因为哈希的原理是将输入空间的值映射到哈希空间中,而哈希值的空间远小于输入空间
根据抽屉的原理:不同的输入肯定会映射到相同的输出中。
抽屉原理
桌子上有10个苹果。要将这十个苹果放入九个抽屉中,无论您如何说,我们都会发现至少有两个苹果中至少有一个抽屉。这种现象就是我们所说的抽屉。
哈希图的简要说明:
哈希图扩展机制的简要说明
hashmap ==阵列 +链接列表 +红色和黑树
因此,获得树木的条件:链接的列表值大于8,并且桶的数量大于树木化前的64(数组长度)。
将元素放入枪管中,定位枪管方法:阵列为bidd时使用目标桶位置I的计算方法。
为什么容量扩展存储桶的数量(数组长度)而不是直接树化?
hashmap功能:
注意:与直接读取哈希图源代码相比,第一个调试更容易理解。
测试代码:
输出结果:
执行过程分析:
示例:如果计算的索引为3,则将其存储到以下桶位:
阐明:
具体原则将在下面进行详细分析。在这里,我们可能会理解您在面试时会问什么,并阅读源代码,并带有问题以促进理解!
1.如何实现HashMAP中的哈希函数?还实施了其他哪些哈希功能?
2.当两个对象的哈希码相等时会发生什么?
会有哈希碰撞。如果密钥值的内容相同,则更换旧值。否则,它将连接到链接列表的背后。链接列表的长度超过8,哈希表长度超过64。
3.什么是哈希碰撞以及如何解决哈希碰撞?
只要由两个元素计算得出的哈希值,就会发生哈希碰撞。哈希碰撞。
4.如果两个键的哈码值相同,则如何存储键值?
平等内容是否相同。
从继承系统可以看出:
知识扩展:
通过上面提到的继承关系,我们发现一个非常奇怪的现象是Hashmap继承了AbstractMap类,并且AbstrackMap实现了MAP接口。那么,为什么HashMap意识到MAP接口?此结构也位于ArrayList中的LinkedList中。
根据Java Collection Framework的创始人Josh Bloch的说法,这是一个错误。在Java Collection框架中,有很多这样的方法。当Java Collection框架起初写成时,他认为这样的写作在某些地方可能很有价值,直到他意识到这一错误。
在Java中,Hashmap实现(数组 +链接列表 +红色和黑树)的实现具有复杂的结构。阵列的一个元素也称为桶。
添加元素时,将根据哈希值计算元素的位置。如果该位置没有元素,则该元素直接放置在此处。如果位置具有元素,则该元素以链接列表的形式以链接列表的形式以链接列表的形式以链接列表的形式形式放置,以链接列表的形式。链接列表的尾巴。
当链接列表的元素数量达到一定数量(阵列的长度达到一定长度)时,链接列表将转换为红树和黑树以提高效率。
数组的查询效率为O(1),链接列表的查询效率为O(k),红树和黑树的查询效率为O(logn)。n是枪管中的元素数量。将红色和黑树转化为大大提高效率。
收集的初始化能力(必须为n次2次):
访谈问题:为什么必须是设定容量2的n时间功率?如果输入值不是2次,该怎么办?
hashmap构造函数可以指定集合的初始化能力,例如:
根据上述说明,我们已经知道,在将元素添加到hashmap中时,我们需要根据键的哈希值确定数组中的特定位置。在访问效率和降低碰撞的顺序中,哈希图是分配尽可能多地数据。每个链接列表的长度大致相同。该实现的关键是存储链接列表的算法。
该算法实际上是一种成型,哈希%长度,并且在计算机中找到平衡的直接效率不如排量操作。长度等于哈希&(长度-1)。
例如,当阵列的长度为8时,枪管的位置为(数组的索引)3和2。在不同的位置,它不会碰撞。
让我们看一下阵列长度(枪管数字)的情况,不是2次:
从上图可以看出,当数组的长度为9(n次n次n次)时,不同的哈希值对数组的竞标相等(非常易于发生)。
同样,使用2次使用hashmap阵列容量的原因:(我会问是否会问面试)
问题:如果创建了hashmap对象,则输入数组长度的长度是多少,而不是2的n时间功率?
hashmap双构建功能将获得n倍的n倍,是最接近长度且大于长度的2个功率的n倍(初始容量)。
这件作品更难理解。描述构造方法时,将为以下示例提供一个示例:
阐明:
当实例化hashmap实例时,如果给出了初始容量,则因为哈希图的容量必须是2的二级功率,则该方法用于找到大于或等于初始容量的最小第二功率。
分析:
因此有结果。执行该方法时,获得的新容量是初始容量2的2个功率的2个功率的2个功率的n次数,并且大于2个2的2个时间功率。
默认负载因子(默认值为0.75)
最大容量
当链接列表的长度超过8时
访谈问题:为什么哈希图桶中的节点数量超过8,以转变为红树和黑树?
8该值的定义是在哈希图中定义的。对于此成员变量,仅显示8是从链接列表结构到树的桶桶的值,但它不能解释为什么它是8
Hashmap中有评论说明:
treenodes(树)职业空间是普通节点的两倍,因此,只有当存储桶包含足够的节点以变成时间座时,但是足够由reeify_thresh 0ld的值确定,当存储桶中的节点数量较少时,它将变得更少变成普通的存储桶,当我们查看源代码时,我们发现链接列表的长度达到8并变成红色和黑色树。当长度降至6时,它变成了普通的桶。
通过这种方式,它解释了为什么它在开始时没有将其转换为时间,但是它需要将一定数量的节点转换为时间座。简单地说,权衡时间和空间。
该内容还提到了:当哈希码离散良好时,树箱的概率将很小,因为我的数据均匀分布在每个垃圾箱中,并且几乎没有bin链接的树木链接列表。随机的哈希码,离散类型可能会变得很差。但是,JDK无法阻止用户获得这种不良哈希算法,因此它可能会导致数据分布不均匀。在理想的情况下,在随机哈希码算法下,所有bin中间节点的分布频率将遵循POSON的分布。我们可以看到,bin链接列表长度为8个元素的概率为0.00000006,这几乎是不可能的。因此,选择8个的原因不是偶然的决定,而是基于概率统计。已经开发了将近30年的Java的变化和优化是非常严格和科学的。
访谈答案:HashCode算法下所有桶的分布将遵循POSON的分布。目前,枪管中链接列表中8个以上元素的概率很小,称重空间和时间复杂,因此选择数字8。
扩展补充剂:
POSON中分布的参数A是单位时间(或单位区域)内随机事件的平均数量。Poison分布适合描述单位时间内随机事件的数量。
当hashmap中的数字超过此值时,表中的水桶可以基于树,否则枪管中的元素将扩大容量而不是树木化,以避免扩展和树化选择之间的冲突。此值不能小于4* treeify_threshold(8)
当链接列表的值小于6时,它将从红树和黑树转换为链接列表
表用于初始化(长度必须为2次2次)
在JDK1.8中,我们了解到Hashmap是由数组加上链接列表以及红色和黑树组成的结构。其中,表是hashmap中的数组。以前的阵列类型JDK1.8是输入条目
用于存储缓存
hashmap中的元素数量
大小是hashmap中k -v的真实时间数,而不是表格的长度。
用于记录哈希图结构的修改数量
用于调整下一个容量值的计算方法是:(容量 *负载因子)
哈希表的负载因子(默认为0.75)
阐明:
为什么负载因子负载因子设置为0.75,而初始化的临界值也为12?
负载因子越接近阵列中的数据越多,链接列表的长度就越密集,较小的数据就越少,较薄的较薄越稀疏。
如果您希望链接列表尽可能小,提前扩展容量,则可能不会将一些数组空间存储在数据中,并且负载因子尽可能小。
例子:
因此,有必要考虑数组利用率并考虑太多链接列表。在大量测试之后,0.75是最好的解决方案。
Hashmap中有四种结构方法,如下:
构建一个空的hashmap,默认初始化容量(16)和默认负载系数(0.75)
构建具有初始指定容量和默认负载系数的哈希图(0.75)。
阐明:
至于问题?
Tablesizefor(初始容量)确定指定的初始化容量是否为n次2次,如果不是这样,它将成为最小的2个功率,比指定的初始化能力大2倍。
但是请注意,计算表Zizefor方法后的数据将返回此处调用,并将其直接复制到Thresold边界值。有些人认为这是一个错误,应该以这种方式写下:
这符合纱线的含义(当哈希图的大小达到戴维的值时,它将扩展)
但是请注意,在JDK 1.8之后的构造函数中,表的成员变量未初始化。表的初始化被推迟到PUT方法。在一次调用PUT方法时的PUT方法中,调用大小为表的数组长度)。
包含另一个地图的施工功能:
注意:
面试问题:为什么在此行代码中添加1.0F?
结果,小数,加上1.0F和int ft等同于组成一个小数和固结小数,以确保尽可能多的容量,更大的土地容量可以减少改装()土地的数量(用于效率,您应该尽可能最大程度地减少扩建土地的数量。
例如:原始数量为6,然后6 / 0.75为8,因为8是2次,然后
执行后,新数组的大小为8。然后,原始数组的数据将存储在一个长度为8的新数组中。并将降低性能。它变为16,可以减少阵列的扩展。
节点是典型的单连接列表节点。其中,哈希用于存储由键计算的哈希值。
treenode内部类,它从linkedhashmap中的输入类继承。在linkedhashmap.entry类将分别发布之后,treenode是典型的树节点。其中,链接列表中的一个节点是删除元素元素的节点。您可以快速找到其前节点。
PUT方法相对复杂,实现步骤大致如下:
具体方法如下:
阐明:
从以上,我们可以知道哈希图支持键空,并且hashtable使用键来获取哈希码,以便钥匙会为空气抛出异常,为空的会议抛出异常。
解释上述哈希方法:
让我们研究如何计算键的哈希值。KEY的哈希值是通过上述方法计算的。
该哈希方法首先将Key的哈希码分配计算为H,然后二进制入口是不同或通过鲁ck或最终哈希值获得的。
PUTVAL函数中以上哈希函数计算计算的哈希值:
计算过程如下所示:
阐明:
最后获取0101 ==>竞标为5桶
简单的说:
高度16位没有变化,低16位和高度16位进行不同或操作(哈希尺寸转换为32位二进制,第一个16-位和后部16-位,低16位,高度16位。做到)。
问题:你为什么这样做?
如果组的长度很小,则假设它为16,则n -1为1111。此值和哈希码直接遵循位置和操作。实际上,仅使用了哈希值的最后4位数字。高价值的高度变化很大,低位置变化很小,因此很容易引起哈希冲突,因此此处使用了高位和低位置解决音乐问题。
在下面,让我们看一下Putval方法,看看它做了什么。
主要参数:
putval方法源代码如下:
扩展机制:
当Hashmap扩展时,Rehash方法非常聪明,因为每个扩展都会加倍。与原始(n -1)&哈希结果相比,它只是一点点,所以节点要么是节点。在原始位置,要么将旧位置分配给原始位置+旧容量。
例如,当我们从16扩展到32时,具体更改如下:
因此,在重新计算哈希后,由于n变为两次,n -1的标记范围在高级别上为1位(红色),因此在新索引中会发生这种变化。
阐明:
5它是计算出的原始索引,因此上述旧验证:在容量扩展后,所有节点均处于原始枪管位置,或者旧时分配给原始位置 +旧容量。
因此,当我们扩展hashmap时,我们不需要重新计算哈希。只需查看原始哈希值的位为1或0.Location+旧容量,您就可以查看32张扩展的Ryze示意图。
正是由于这种巧妙的重新进行方法,它不仅要重新计算时间计算时间,同时,因为新的1位是0或1可以认为是累积的,每个桶都在在调整大小的过程中保证了重新仪。上面的节点的数量必须小于原始枪管上的节点的数量,这确保了重新旋转后不会发生更严重的哈希冲突,并且先前的冲突节点将分散到新桶。
源代码调整方法的解释:
删除的方法是首先找到元素的位置。如果您用红色和黑树横穿树并在找到它后将其删除。当树小于等于6时,必须将其转换为链接列表。
删除删除方法:
remoevnode方法:
找到该方法,通过元素键找到值。
代码显示如下:
GET方法主要称为GetNode(),代码如下:
概括:
分别遍历钥匙和值
使用迭代器迭代脚趾
通过GET方法(不建议)
阐明:
根据ALI开发手册,不建议使用此方法,因为迭代两次,Keyset一次获得迭代器迭代器,并且它通过降低性能而进行一次迭代。
遍历代码: