从线性探测转向二次探测(哈希冲突)

2023-12-13

我当前的哈希表实现是使用线性探测,现在我想转向二次探测(后来转向链接,也许还有双重哈希)。我读过一些文章、教程、维基百科等......但我仍然不知道我到底应该做什么。

基本上,线性探测的步长为 1,这很容易做到。当从哈希表中搜索、插入或删除元素时,我需要计算哈希值,为此我这样做:

index = hash_function(key) % table_size;

然后,在搜索、插入或删除时,我循环遍历表,直到找到一个空闲的存储桶,如下所示:

do {
    if(/* CHECK IF IT'S THE ELEMENT WE WANT */) {
        // FOUND ELEMENT

        return;
    } else {
        index = (index + 1) % table_size;
    }
while(/* LOOP UNTIL IT'S NECESSARY */);

至于二次探测,我认为我需要做的是改变“索引”步长的计算方式,但这就是我不明白应该如何做。我看过各种代码,它们都有些不同。

另外,我已经看到了二次探测的一些实现,其中哈希函数被更改以适应这种情况(但不是全部)。是否真的需要进行这种更改,或者我可以避免修改哈希函数并仍然使用二次探测吗?

EDIT:在阅读了 Eli Bendersky 下面指出的所有内容后,我想我已经有了总体想法。这是代码的一部分http://eternallyconfuzzled.com/tuts/datastructs/jsw_tut_hashtable.aspx:

15   for ( step = 1; table->table[h] != EMPTY; step++ ) {
16     if ( compare ( key, table->table[h] ) == 0 )
17       return 1;
18 
19     /* Move forward by quadratically, wrap if necessary */
20     h = ( h + ( step * step - step ) / 2 ) % table->size;
21   }

有两件事我不明白......他们说二次探测通常是使用c(i)=i^2。然而,在上面的代码中,它所做的事情更像是c(i)=(i^2-i)/2

我准备在我的代码上实现这一点,但我会简单地这样做:

index = (index + (index^index)) % table_size;

...并不是:

index = (index + (index^index - index)/2) % table_size;

如果有的话,我会这样做:

index = (index + (index^index)/2) % table_size;

...因为我见过其他代码示例下降了两倍。虽然我不明白为什么...

1)为什么要减去步骤?
2)为什么它会下降 2 倍?


如果您的表大小是 2 的幂,则有一种特别简单而优雅的方法来实现二次探测:

step = 1;

do {
    if(/* CHECK IF IT'S THE ELEMENT WE WANT */) {
        // FOUND ELEMENT

        return;
    } else {
        index = (index + step) % table_size;
        step++;
    }
} while(/* LOOP UNTIL IT'S NECESSARY */);

Instead of looking at offsets 0, 1, 2, 3, 4... from the original index, this will look at offsets 0, 1, 3, 6, 10... (the ith probe is at offset (i*(i+1))/2, i.e. it's quadratic).

这保证会命中哈希表中的每个位置(因此,如果有的话,您一定会找到一个空桶)provided表的大小是 2 的幂。


这是证明的草图:

  1. 给定一个 n 的表大小,我们想要证明我们将得到 n 个不同的值 (i*(i+1))/2 (mod n),其中 i = 0 ... n-1。
  2. 我们可以用反证法来证明这一点。假设有少于 n 个不同的值:如果是这样,则 i 在 [0, n-1] 范围内必须至少有两个不同的整数值,使得 (i*(i+1))/2 (mod n )是一样的。称这些为 p 和 q,其中 p
  3. 即 (p * (p+1)) / 2 = (q * (q+1)) / 2 (mod n)
  4. => (p2 + p) / 2 = (q2 + q) / 2 (mod n)
  5. => p2 + p = q2 + q (mod 2n)
  6. => q2 - p2 + q - p = 0 (mod 2n)
  7. 因式分解 => (q - p) (p + q + 1) = 0 (mod 2n)
  8. (q - p) = 0 是简单的情况 p = q。
  9. (p + q + 1) = 0 (mod 2n) 是不可能的:p 和 q 的值在 [0, n-1] 范围内,并且 q > p,因此 (p + q + 1) 必须在范围 [2, 2n-2]。
  10. As we are working modulo 2n, we must also deal with the tricky case where both factors are non-zero, but multiply to give 0 (mod 2n):
    • 观察两个因子 (q - p) 和 (p + q + 1) 之间的差是 (2p + 1),这是一个奇数 - 因此其中一个因子必须是偶数,另一个必须是奇数。
    • (q - p) (p + q + 1) = 0 (mod 2n) => (q - p) (p + q + 1) 可被 2n 整除。如果 n(因此 2n)是 2 的幂,这要求偶数因子是 2n 的倍数(因为 2n 的所有质因数都是 2,而奇数因子的质因数都不是)。
    • 但 (q - p) 的最大值为 n-1,(p + q + 1) 的最大值为 2n-2(如步骤 9 所示),因此两者都不能是 2n 的倍数。
    • 所以这种情况也是不可能的。
  11. 因此,(步骤 2 中)少于 n 个不同值的假设必定是错误的。

(如果表大小为not2 的幂,这在第 10 步就崩溃了。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从线性探测转向二次探测(哈希冲突) 的相关文章

  • 集群():是否可以仅检查文件是否已锁定,而不实际获取锁定(如果没有)?

    我的用例如下 我有一个程序 它强制在任何给定时间只能运行它的一个实例 因此在启动时它总是尝试在标准位置获取锁定文件 并在该文件终止时终止已经被锁定 这一切都工作正常 但现在我想用一个新的命令行选项来增强程序 当指定该选项时 将导致程序只打印
  • 全局变量不好

    好吧 读完这篇文章和一些示例后 我仍然不清楚全局变量的含义 那么你的类中的私有变量是全局的吗 http www c2 com cgi wiki GlobalVariablesAreBad http www c2 com cgi wiki G
  • 如何获取枚举数作为常量?

    From 枚举中定义的项目总数 https stackoverflow com questions 856154 total number of items defined in an enum 我发现我可以使用以下方法获取枚举数 Enum
  • 处理器关联组 C#

    我使用的是 72 核的 Windows Server 2016 我看到有两组处理器 我的 net 应用程序将使用一个或其他组 我需要能够强制我的应用程序使用我选择的组 我看到下面的代码示例 但我无法使其工作 我可能传递了错误的变量 我希望应
  • 图片框、双击和单击事件

    我有一个奇怪的问题 我有一个图片框双击事件以及单击事件 问题是即使我双击该控件 也会引发单击事件 如果我禁用单击事件 则双击事件正在工作 这个问题已经在这里讨论过 https stackoverflow com questions 1830
  • 如何在单例类和未命名类之间进行选择?

    我会使用这样的单例 Singleton single Singleton instance single gt do it 我会使用这样的未命名类 single do it 我觉得单例模式除了具有可读的错误消息之外 与未命名的类相比没有任何
  • C++:避免​​在重载中将字符串自动转换为布尔值

    我想创建一组方法 这些方法将根据其类型输出具有特殊格式的值 当我这样做时 到目前为止看起来还不错 static void printValue std ostringstream out int value out lt lt value
  • 我应该使用字节还是int?

    我记得曾在某处读到 即使您只需要字节 使用 Int32 更好 就性能而言 它 据说 仅适用于您不关心存储的情况 这是有效的吗 例如 我需要一个保存一周中某一天的变量 我是吗 int dayOfWeek or byte dayOfWeek E
  • .Net 支持柯里化泛型吗?

    假设我们有一个嵌套的泛型类 public class A
  • 来自同一基模板类的 C++ 重写函数,具有多重继承不明确的函数调用

    我需要打电话init int iNumber 从基类派生的函数 基类 h pragma once include stdafx h template
  • Qt 多重继承和信号

    由于 QObject 我在 QT 中遇到了有关多重继承的问题 我知道很多人也有同样的问题 但我不知道该如何解决 class NavigatableItem public QObject Q OBJECT signals void desel
  • ArrayList 有什么问题?

    最近我问了一个关于 SO 的问题 其中提到了可能使用 c ArrayList 来解决问题 有人评论说使用数组列表不好 我想了解更多有关此的信息 我以前从未听说过关于数组列表的这种说法 有人可以带我了解使用数组列表可能出现的性能问题吗 C n
  • 为什么使用 .AsEnumerable() 而不是转换为 IEnumerable

    扩展方法之一IEnumerable
  • 在 OSX 上检测 Objective C 或 C++ 中的文件夹访问(如 fs_usage 命令)

    我正在 OSX 上开发实时病毒扫描程序 OSX 的命令行命令fs usage可以通过以下方式确定文件夹访问权限 并且只能以 root 用户身份运行 fs usage w f pathname grep Users Documents Use
  • 如何检查日期时间是否发生在今天?

    有没有比下面的代码更好的 net 方法来检查 今天 是否发生了 DateTime if newsStory WhenAdded Day DateTime Now Day newsStory WhenAdded Month DateTime
  • 对 Action 方法的两个并行 ajax 请求排队,为什么?

    我正在使用 ASP NET MVC 开发一个视频网站 我希望在我的应用程序中拥有的一项功能是转码视频 但由于转码过程可能非常耗时 我想向客户端用户展示该过程的进度 因此 我的架构是使用一个控制器操作来处理整个转码过程 并将其进度写入存储在服
  • C 中的等效 plpgsql 触发器

    我有一个 PostgreSQL 9 0 服务器 并且在某些表上使用继承 因此我必须通过如下触发器模拟外键 CREATE OR REPLACE FUNCTION othertable before update trigger RETURNS
  • 将“C# 友好类型”名称转换为实际类型:“int” => typeof(int)

    我想得到一个System Type给定一个string指定 原始 类型C 友好名称 基本上与 C 编译器读取 C 源代码时的方式相同 我觉得描述我所追求的最好方式是单元测试的形式 我希望存在一种通用技术 可以使以下所有断言通过 而不是尝试对
  • Web 和 winforms 的 .Net 身份验证

    我有一个为客户端构建的 ASP NET Web 应用程序 它使用默认的 ASP NET 表单身份验证 他们现在请求一个能够 与 Web 应用程序一起工作的桌面 WinForms 应用程序 我已经创建了 Web 服务来访问他们想要从 Web
  • 在派生类中访问基类变量

    class Program static void Main string args baseClass obj new baseClass obj intF 5 obj intS 4 child obj1 new child Consol

随机推荐

  • 如何在没有QProxyStyle的情况下修改样式提示?

    我使用 Qt 的 Python 绑定 PySide 或 PyQt4 他们没有QProxyStyle 我想更改样式提示的值 例如改变SH Menu SubMenuPopupDelay子菜单弹出延迟时间 在本机 C Qt 中我会使用QProxy
  • Python - 斐波那契函数变量值声明之间的差异

    我是 python 的初学者 我正在研究一种制作斐波那契函数的类型 def fib n a 0 b 1 while a
  • AdMob 广告单元 ID 需要多长时间才能生效?

    大约 4 小时前 我创建了一个新的广告单元 ID 并开始在未发布的 Android 应用程序的发布版本中使用它 但我得到的只是一个空白视图和以下 logcat 输出 W Ads Received error HTTP response co
  • 使用 getElementsByClassName 操作样式[重复]

    这个问题在这里已经有答案了 我不明白为什么我无法在代码中操纵 special 的样式 我确信这很简单 但它不起作用 h1 I am an h1 h1 p class special Hello p p class special Goodb
  • ADF 从代码手动调用操作

    我想从按钮 ActionListener 执行数据控制操作 CreateInsert 和 Delete 我知道可以从 数据控件 菜单插入数据控制按钮 但由于各种原因我需要这样做 其中一个突出的原因是我需要执行额外的运行时检查 我找到了以下代
  • Python 随机无重复

    这是我的代码 我试图用 0 6 之间的 7 个数字填充一个列表 没有重复 并且每次都是随机顺序 这是我的代码 但我不断收到错误 列表分配索引超出范围 但我不知道我的错误在哪里 这是我的代码 import random def generat
  • 高级 C 问题:请解释 C 构造 *({ foo(&bar); &bar; })

    这最终是在研究Linux内核源代码的completion h中的代码时出现的一个C问题 在那里我看到了我以前从未在C中使用过的C技术 虽然对它在做什么有一个模糊的感觉 但我想用精确的描述来调整我的理解 而且我不太确定如何在没有可能漫长的考验
  • 使用 PHP 时,我可以使用 JDBC 或 ODBC 连接吗?

    我有一个 PHP 应用程序 我想从 MySQL 切换到 Cache DB 我想知道是否可以使用 JDBC 或 ODBC 连接 因为 Cache 不附带 PHP 连接 Thanks PHP 可以使用 ODBC 连接directly或通过PDO
  • JPA 枚举的映射集合

    JPA 有没有办法在实体类中映射枚举集合 或者唯一的解决方案是将 Enum 与另一个域类包装并使用它来映射集合 Entity public class Person public enum InterestsEnum Books Sport
  • 斐波那契数列的负输出

    尽管使用了斐波那契数列 但在添加大量数字时 我得到了负输出long int 如何解决这个问题 include
  • Hibernate - 复合主键包含外键

    我有一个类似的问题如下 但解决方案并没有解决我的问题 hibernate复合主键包含复合外键 如何映射这个 我正在尝试连接两个表 每个表都有一个带有部分外键引用的复合主键 Table A f1 pk f2 pk f3 pk f4 pk Ta
  • 如何阻止特定应用程序访问我的网站

    有人有一个应用程序 Android 可以访问我的网站并显示一些页面 我本来可以接受它 除非该应用程序有一些错误 并且使用它的人无法使用该网站的某些功能 我怎样才能阻止这个特定的应用程序 附 我拥有对我的网络服务器的根访问权限 并且它是专用的
  • LD_LIBRARY_PATH

    我可以为单个应用程序设置 LD LIBRARY PATH 吗 我正在调查系统调用失败 那么有什么方法可以使用 LD LIBRARY PATH 设置设置正确的路径 最简单的方法是创建一个 shell 脚本 让 shell 脚本导出新的 LD
  • 使用 dompdf 生成 pdf 图像时出错

    我必须在生成的 PDF 的每一页中显示徽标 虽然它在本地系统中工作正常 但在服务器中抛出以下异常 Fatal error Uncaught exception PDFlibException with message Handle para
  • 如何在 JScrollPane 中获取 JScrollPanes 以跟随父级的大小调整

    所以我有一堆JTables Each JTable是在一个里面JScrollPane 然后我将添加其中的每一个JScrollPanes to a JPanel 然后我添加这个JPanel to a JScrollPane然后到另一个JPan
  • 为什么我无法用 Prolog 得到 Ship Puzzle 的答案?

    我需要使用 Prolog 解决 Ship Puzzle 问题 以下是事实 有5艘船 希腊的船六点出发 载着咖啡 中间的船有一个黑色的烟囱 英国船九点出发 有蓝色烟囱的法国船位于一艘运载咖啡的船的左侧 运载可可的船的右侧是一艘开往马赛的船 这
  • 检测序列的排列

    我有一个像这样的数字列表 数组 1 2 3 4 所以我的目标是检查给定的另一个数组 如果该数组是原始示例的排列 则该数组 3 4 1 2 and 1 2 4 3 是原始的排列 但是 1 2 1 1 or 1 5 4 3 not 两种可能的解
  • 确定重叠 DATETIME 范围的最大数量

    我有一张桌子 上面有一些DATETIME范围 比如 id start end 1 2011 12 18 16 00 00 2011 12 18 17 00 00 2 2011 12 19 08 00 00 2011 12 19 10 00
  • 何时从 QAbstractItemModel 发出 dataChanged

    在 Qt 中 我有一个模型子类化QAbstractItemModel 它是显示在 QTreeView 中的树 该模型支持各种形式的更改 并且都可以正常工作 相关的两个是 1 少量相关行中的部分数据发生变化 2 可视化更改意味着大多数行应更改
  • 从线性探测转向二次探测(哈希冲突)

    我当前的哈希表实现是使用线性探测 现在我想转向二次探测 后来转向链接 也许还有双重哈希 我读过一些文章 教程 维基百科等 但我仍然不知道我到底应该做什么 基本上 线性探测的步长为 1 这很容易做到 当从哈希表中搜索 插入或删除元素时 我需要