HashMap实现原理

引出Hash

给你N (1<N<10)个自然数_每个数的范围为(1~10000)。现在让你以最快的速度
判断某一个数是否在这N个数内,不准用现成的HashMap ,比如
N:5
10 50 60 1 5
判断5在不在上面的5个数当中
foreach //从头到尾查找的效率是 O(n)
二分法:二分查找,前提条件是有序 效率就为排序的效率+二分的效率,为:O(nlogn)
Hash : int a[]=new int[n];数组的下标表示序列里面的数a[5] 下标就是0,1,2,3,4, 通过下标去找效率为: O(1)
最开始把 a数组全部置位0
a[0] = 0表示0不存在我们的n个数中
a[l] = 1表示1存在n个数中
a[10] = 1
判断7那么我只要判断a[7]是不等于1不就ok了? a[7] O(1)的效率有点像我们的数据库的hash索引,只不过我们用的是下标

解决冲突

上面说到的是开了一个数组来存储, 但是如果我们的数字为 : 1,5000,10001 为了存储这三个数岂不是要开一个长度为10000的数组, 结果里面就存了三个数
说到这,我们可以改进一下我们的数组,就是为其写一个特定的规则,比方说我们为其取模.
这样问题就简单的多了

哈希函数

现在我们遇到的问题是有三个数,但是我们要是根据数字大小去放到数组中对应的位置的话,内存浪费的太严重, 如果说这个数字是天文级的, 不要说内存浪费,是直接开辟不出这么大的内存
所以我们要想办法,让三个数按照一定的规则来存放到数组中,这个规则我们就可以理解为广义的哈希函数,比如说,11,22,1005,这三个数字有个特点, 就是末尾都是不一样的, 我们可以假设一个规则是这样的
个位数是几, 就放到对应的数组索引下标里面去, 所以我们的数组存储过这三个数之后应该是这样的[0,11,22,0,0,1005], 这时候我们想找有没有1005,直接找 arr[5],能返回回来就是有, 返回不出来就是没有

挂载红黑树

通过上面的方法我们使用了 O(1)的效率找到了数组中的元素,遍历数组已经不可和哈希的效率同日而语, 但是现在又出现了一个亟待解决的问题,就是如果我们的数组中要存储的为 11,21,1005怎么办, 按照我们之前的
方法, arr[1]中应该存储11, 现在又出校一个21, 怎么办? 我们可以想到使用二位数组, 就是 arr[1]中依然存储一个数组.这种是可以的.现在我们思考的和JDK中的HashMap实现非常相似了.
JDK中是如何实现HashMap的呢,我们知道数组的实现本质上是因为我们现在使用的RAM是随机存取存储器,硬件上的特性决定了RAM可以根据索引快速存取数据, 这也是决定Hash为什么这么快的科学依据.
但是当是使用二维数组的时候,遍历又变慢了, 经过了大量的数据认证, 最后JDK中使用了8个以下用数组,8个以上用红黑树的策略.8个以上的数据经过红黑树来存取,速度达到了最优.这也是HashMap非常快的原因

posted @ 2020-10-20 21:14  Terry-  阅读(79)  评论(0)    收藏  举报