Hash为什么快

hash查找的时间复杂度是constant(常量)级的,也就是O(1),它是怎么做到的呢?
先举个例子:

如果在[0,1,3,4,7,9]这个数组中找到某个数字,比如:4 or 6,那么需要遍历这个数组一次,时间复杂度是O(n)。如果使用二分查找法,时间复杂度是logn。

但现在,我们如果在内存中开辟一个连续的空间,并将这个数组按如下位置放入。

0 1 2 3 4 5 6 7 8 9
0 1 3 4 7 9

这样我们已经知道每个值的地址是多少,例如:一个整数占4字节(即32bit),以0的位置开头为start,那么找到4这个整数的起始位置就是:start+4*32,也就是O(1)的时间复杂度即可拿到4数组中的那个位置的值,判断4是否在数组中。

好,我们接下来扩展一下上面这个问题

如果数组中的不是整数,而是字符串,比如:[“bob” , “jony” , “jack” , “neo”],每个字符串的长度不一样,那我们怎么对应到可以直接计算地址的表里面呢?
如果我们有一个算法,可以将上面的每个字符串计算成统一长度的字符串甚至是直接计算成整数,比如”bob”计算出来等于0,”jony”=1,”jack”=4,”neo”=8。那么数组就可以存储进如下的表中了:

0 1 2 3 4 5 6 7 8 9
bob jony jack neo

如果查找一个名字”bob”是否在这个数组中,那么我们可以先用这个算法计算一下”bob”这个字符串,得到0,直接查找0这个位置的值,如果查找”bill”这个名字是否在数组中,计算”bill”=6,发现这个位置没有值,判断这个名字不在数组中。

上面说的这个算法,即是Hash算法,这张表,即是Hash表。
Hash算法(又称散列算法)定义如下:把任意长度的输入,通过散列算法,变成固定长度的输出,这个输出即为hash值。

这种转换是一种压缩映射,也就是散列值的空间远远小于输入值的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。不同输入产生相同的输出的情况我们即称之为hash碰撞(或Hash冲突),这种情况我们一般会在当前的hash值下再挂一个链表,Java中HashMap就是这么实现的,为了提高链表上的查找效率,Java8中在链表上数据超过8之后,会将链表变为红黑树。

猜你喜欢

转载自blog.csdn.net/u011305680/article/details/80292961