[15-445]Hash tabels memo
这一章大概是一个 hash tables 的科普。因为刚上课不久 andy 就说我们自己不会去实现一个这玩意儿。现在有非常优秀的方案,你应该去使用那个最好的方案,那个方案把其他方案都给碾碎了。我们当然就应该使用它。
xxhash 是之前搞 zstd 的 facebook 哥们搞的。这俩玩意儿一个是最好的压缩算法之一,一个是最好的 hash 算法。
这里 hash 算法谈论好,我们暂时忽略加密性能,单纯从我们一个 input 到输出一个固定长度,最少碰撞的角度去说
可以看到 xxhash 在 > 64byte key 的情况下约比 google 的 cityhash 快约 3倍。。
STATIC HASHING SCHEMES
首先所有静态冲突检测都基于一个原则,如果我们发现不过怎么检测都无法再插入值的时候,我们可以扩大哈希表本身,比如 *2 ,先将之前的值拷贝过去,然后再重新为之前造成死循环的值寻找新的位置。
1. LINEAR PROBE HASHING 解决冲突的模式还比较好理解。我们使用 hash 函数对值进行计算,然后找到对应的槽放置数据。如果有冲突了需要继续沿着槽顺序检查下一个槽是否有数据,
如果没有就放置。
那么这种方案如果遇到中间被删除了一个元素,顺序查找被打断又该如何,有两种方案
1. 全部重新算一次,将对应的数据重新放置回对应的问题。
2. 使用墓碑标记,标记被删除掉的位置。这样在扫描的时候就知道这里的不连续十因为数据删除,那么可以继续向下查找对应值。
2. LINEAR PROBE HASHING 变种 ROBIN HOOD HASHING 它改进了冲突检查的机制。
简单的来说它尝试让发生冲突的 key 不要距离原始冲突位置太远,以此来避免一些极端情况。比如某个 key 因为周围 slot 都满的情况下被调配得距离原始冲突位置过于远。
3. CUCKOO HASHING 使用两个不同的哈希函数来避免冲突。在一个线程中,先做第一个 hash ,如果无冲突就放进去。如果有冲突就做第二个 hash,如果无冲突就放进去,如果还是有冲突就盗取该位置,并且将该位置的值重新拿去计算 hash 直到找到一个可以放置的的 hash。拿冲突位置的 key 去看是第一个 hash 函数产生的还是 第二个 hash 函数参数产生的。如果最后死循环了,就得扩大 hash 表重新计算。
DYNAMICS HASHING SCHEMES
1. CHAINED HASHING,如果发生冲突我们会借助一个链表来存储重复位置的 key。
2. EXTENDIBLE HASHING 基于 CHAINED-HASHING 的一个变种。它解决了一个 CHAINED-HASHING 的问题,CHAINED-HASHING 可能会因为需要解决冲突而无限让 linked-list 扩展。CHAINED-HASHING 通过分裂桶来替换让 linked-list 无限扩张。
3. LINEAR HASHING,同样是基于 CHAINED-HASHING 的一个变种。主要是为了解决 slot 和 bucket 扩展的时候引起的性能问题我理解。因为使用 LINEAR HASHING 可以最大限度的防止一次扩展太多导致的性能问题,每次触发都只扩展一部分,直到全部扩展完毕后停用之前的 HASHING 函数查找值。
这个例子当我们插入值 17 的时候 overflow 了,需要扩展 slot1 才能装下。但是我们不扩展 slot-1 而是通过 split-pointer 扩展 slot-0。
于是我们通过新的 hash function 会得到槽 4。
通过新的 hash function key%2n 我们得知 20 将不再存储在 slot 0 而应该存储在 slot 4。我们就此扩展出 slot 4,并且移动 split pointer。这个时候查找插入元素大于等于 slot 1 的使用老的 hash function,小于 1 的需要使用新的 hashfunction。
那么这时其实 17 还是借助辅助数据结构在外,我们需要再等到一个 overflow 就可以扩展 slot-1,这个时候我们能扩展出 slot-5。这时 17 就可以移过去了。
等所有的 slot 都扩展过一次, split-pointer 将会移回初始位置,并且删除 hash func-1。重新开始上面的循环。
ps:
我个人没有太理解 expended-hashing 的操作,也找了一些资料看,看感觉看懂了 但是没有到完全吃透的感觉。可以需要动手写一写理解更深一些。我会到时候再回过头来补充一些内容。
Reference:
https://www.bilibili.com/video/BV1xa41137S4?p=7&vd_source=d05baeb2783257f3e6b27121e7a796a0
https://github.com/facebook/zstd
https://github.com/Cyan4973/xxHash