传统hash表是将key的hash值与value的数组下标对应实现,也就是将key的hash值经过某种运算得到一个整数值,这个值就是value列表的下标,就是key对应的value值
下面描述几个常用的概念:
打个比方:md5计算,就是无论多大的数据传入,出来的都是128位长度,即32位的16进制字符串,128位可以代表的个数是2^128-1个?,理想情况下如果我使用2^128个数插入,是不是就一定会导致冲突。当然和具体的算法也有关系,好的算法,可以尽量避免冲突。
部分概念说明:
插入流程:
1 计算key的64位hash值,并分为H1:高57位,H2:低7位
2 找到起始group id,并且依照顺序检查group,看是否key在此group中,起始group id是startIdx = H1 & (numGroups - 1) // numGroups 是 2 的幂;numGroups就是group的数量,如果在起始group没有,那么往后找idx_i = (startIdx + (i + i*i) / 2) % numGroups, i = 0,1,2,…,i=0时就是startIdx
3 如何知道key在group中呢?就是通过匹配控制字节;先把H2首位填充0复制扩展7份,那么就是8个H2共8字节,与控制字节进行XOR异或计算,这样只要和H2匹配上的都是0x00,这里还没排除排除控制位的干扰:异或的结果做与计算:xor & 0x7F7F7F7F7F7F7F7F,这样就只保留低7位的计算结果,这样全为0的字节就是与H2匹配的slot了,那么如果提取全为0的部分:
goresult = masked + 0x7F7F7F7F7F7F7F7F
// 上面的操作后,全为0的部分,最高位还是0 ,只要是非0 的部分,最高位是1
result = ^result // 取反,匹配的字节最高位变成 1
result = result & 0x8080808080808080 // 只保留最高位
4 将最高位提取出来:
go最后一步,将 result 的各个字节最高位提取出来,压缩成一个 8 位整数:
bits = (result >> 7) & 0x010101010101010 // 每个字节最高位移到最低位
bits = bits * 0x0101010101010101 // 乘法将所有字节的最低位移到最高字节
bits = bits >> 56 // 取出最高字节(即8个位)
这样一个字节中,1的位置就是对应匹配的了