好的,所以我一直在做一些哈希表和不同的冲突解决问题的实验。我试图找出哪个更有效地进行查找,哈希表使用单独的链接或二次探测来进行冲突解决。我的结果表明,即使对于0.4或0.2等小负载因子,单独链接也比二次探测更快。是这种情况还是我的结果错了?
答案 0 :(得分:7)
两种方法之间 处理成本 的差异在于
(带链接)
- 间接,即指针取消引用
与
(二次探测)
- 评估[简单但复合]算术公式
- 索引到新位置
- 可能的重复(由于探测值与存储在这些位置的非目标值之间的冲突;链接不必担心。
因此链接更快应该不足为奇;指针解除引用是大多数CPU的“本机”指令,与索引到数组中的指令相当(在大多数情况下相同),将算术运算和可能的冲突作为开销而不利于探测。最简单的探测序列公式将需要一些CPU指令(初始化stepNr,通常是stepNr的一些移位,添加到当前位置/探测器),这本身就比指针解除引用慢几倍。 (Poss。警告:此后不久请看'编辑',因为它讨论了链接如何导致更多CPU级别的缓存未命中,从而使其效率低于线性探测)
二次(或其他形式)链接的优点是
考虑这个空间与速度(或者插入时间与搜索时间)以非常宽泛的方式对进行折衷,链接的存储开销(主要针对指针本身,不考虑可能)堆管理开销用于存储[探测内容]“探测位置”的预先计算值。由于这些计算很容易完成,因此链接方法在搜索时更快
编辑(谢谢,Ants Aasma)
这个论点[关于预先计算的位置]的一个警告是,在现代CPU及其缓存上,运行小计算的成本可能远低于在缓存未命中时访问[数据]内存的成本。这表明,探测 顺序 (或更一般地,探测函数产生物理上靠近碰撞点的位置)可能会超出链接策略,因为缓存未命中率较低。在这种情况下,纯顺序探测方法是探测函数中最好的,因为它的计算非常简单,但更重要的是因为它最大化了缓存命中的几率。考虑到这一点,当散列函数具有良好的分布并且载荷因子很小时(因此在初始碰撞之后具有短/局部搜索路径)应该尝试线性(或非常局部)探测方法< /强>;但是,应该避免探测提供非物理本地搜索路径的函数。
很难专门评论问题中提到的实验,例如不知道哈希的大小(如果这个大小与CPU中的单词/寄存器匹配,算术可以更快),或者不知道碰撞比(让我们假设一个好的,分布均匀的哈希函数)
当你不断尝试这个时,收集一组单独的时间/统计数据来访问具有哈希槽的项目与产生冲突的项目将会很有趣。
“ ......即使对于小负载因子...... ”中的“ even ”表示您期望链接的相对优势应该随负载进一步增加因此,随着碰撞变得更多。我也希望情况会如此 此外,增加负载可能会说明探测的另一个缺点:探测周期时的情况和/或更普遍地说,当没有空间适合特定项目时。