hash函数有时依然会超级快,但某些hash函数要⽐其他hash函数快2到3倍
这意味着,我们需要提前知道我想要保存的key的⼤概数量。这样我就知道该如何进⾏分配,我所分配的hash table⾜够⼤能够容纳下这些key,并且最⼩化 hash碰撞,这样我也不会遇上⽆限循环或者是hash table被完全填满的情况了
也被称为 open addressing 开地址法
有一个问题,此时查找D,则会找不到——但他实际是在表中的,有多种方法解决这个问题:
基于线性探测哈希。保存一个所在位置与计算出的位置的距离差,counter越大代表越poor。我们会试着对整个hash table进⾏平衡,劫富济贫,试着让每个key尽可能靠近它原本所在的位置
具体实现方法是,再插入时查看当前元素与下一个元素哪个更poor,距离差更大的会直接使用该位置。例如:
于是:
这看起来很nice,但⾄少,现代研究表明,尤其是对内存中的数据结构来说,只要有⼀次条件误判,你就会付出巨⼤的代价。因为在基于 Robin Hood Hashing算法的情况下,我们需要对更多的条件进⾏检查,看看能否将 ⼀个放到另⼀个的位置上,这样,我们就要做更多的写⼊操作,这导致更多的缓存⽆效。So,在实战中,linear probing hashing依然碾压⼀切
布谷鸟喜欢将它⾃⼰的蛋移到别的⻦巢⾥
使用多个不同的哈希函数(一般用两个),或同一个哈希函数但种子不同。
插入:
查找和删除的时间复杂度始终是O(1),但插⼊操作的代价可能会更加昂贵
——我们不想在出现循环碰撞或表满时重建整个表
相同hash值的key放在同一个chain中,chain关联了多个bucket/page
chain可能过长,我们需要对溢出的bucket进行拆分而不是永远增长下去。
如果像这样溢出:
则增加该桶的局部深度,分裂为两个桶、重排元素、重新映射全局目录中的指针
如果局部桶的深度超过全局,则增加全局深度并映射新添加的目录项
..?
渐进式增加全局目录的大小。在某桶溢出时分裂分裂指针指向的桶:2n取模,然后递增分裂指针
%2n要么分配到原桶,要么分配到新桶
能⽤在我们今天所讲的任何⼀种hashing scheme上
快速测试一个元素是否在一个集合内。存在假阳性但不会有假阴性。使用位数组和多个hash函数表示集合