哈希表调整大小:如何在不知道密钥的情况下执行此操作?

时间:2012-12-08 23:32:10

标签: hashtable

当我们只在哈希表中存储密钥的结果数据时,如何执行哈希表调整大小?我能想到的一个例子是存储用户名&密码组合。为了保护隐私,我们只存储密码(也可能有许多其他用例)。这里,表只存储数据而不存储密钥。鉴于此,如果我想在调整大小期间将旧表中的条目复制到新表,我没有哈希的键。

如何在此处完成调整大小?

4 个答案:

答案 0 :(得分:1)

在这种情况下,你根本就没有真正使用哈希表 - 或者至少你所讨论的哈希没有被用作表的哈希值。

换句话说,密码的散列(例如,SHA-256)只是另一条数据,存储在表中(散列表或其他)。只有在/密码更改时才会进行修改。

它可能存储在哈希表中,例如用户名 - 但如果是这样,你将在这里拥有用户名,这样你就可以在需要时重新哈希。

如果由于某种原因,您决定使用密码的安全哈希作为表中的键,那么完整的哈希将 键,以及您用来索引的内容该表将是该散列的一些散列(例如,所有异或的两个字节块)。

编辑:就表调整大小(单独)来说,不,存储密钥不是绝对必要的。您只需存储原始哈希码的剩余部分即可。换句话说,您通常会先生成一个32位哈希值。然后使用其中的部分(但仅部分)索引到表中(例如,16位)。当需要调整表的大小时,您将获取表中16位的位置,以及存储的其余16位散列的剩余部分以恢复原始的32位散列。假设您将表的大小加倍,那么您将使用17位作为索引,并将剩余的15位存储在表中。

如果您不介意对散列本身感到有点疯狂,您也可以使用它来消除存储密钥的任何实际需要。例如,如果您通过创建256位哈希(例如,SHA-256)开始,则可以使用N位作为哈希表的索引,并将剩余的位用作密钥。如果你的实际密钥长度超过256位,这将导致碰撞的可能性 - 但是与SHA-256的碰撞是非常罕见的,以至于偶然遇到的几率肯定低于计算机错误的可能性。关键的比较,所以它说两个键是相同的,当他们真的不是。

答案 1 :(得分:1)

简短版本:哈希表只能使用其数据的哈希码;他们必须包含实际数据。如果您提供给哈希表的所有内容都是哈希值,那么就是数据。哈希的散列表,这是您试图创建的,不会出现调整大小的问题。就哈希表而言,你插入的哈希是数据,而且为了产生数据而进行的哈希处理是无关紧要的。


长版:

哈希表哈希表是两个正交的想法。听起来你正在以两种情境中没有多大意义的方式混淆两者。

对于散列表,整个点是将键明确映射到值。如果没有这两个,那么表就没用了哈希表使用的哈希码不是,也不能在逻辑上与数据分开 - 它来自数据 ,通常是在飞行中计算的。哈希码的唯一目的是快速定位(或存储)实际的键 - >值映射;你仍然需要一个实际的键和一个实际值来映射。

需要实际密钥的主要原因是,哈希码只是到目前为止。在某种程度上,每个有用的散列表和每个散列函数都固有地由pigeonhole principle绑定。这意味着

  • 根据定义,每个散列函数都可以返回两个不同值的相等散列码;和
  • 每个有用的哈希表都必须以某种方式解决冲突(在相同的哈希码之间和/或指向同一桶的不同哈希码之间)。

Hashtables实际上受到了鸽子原则的双重影响;他们不仅要将数据减少到(通常是int大小的)哈希代码,而且由于大多数哈希表不能合理地拥有40亿个桶,因此代码必须使用该哈希代码进一步减少以将其转换为一个桶号。 (一个常见的例子是将哈希码乘以一些素数, mod 桶的数量。)

即使只读哈希表通常也必须解决冲突。想象一下只读哈希表,它使用一个非常完美的哈希函数,表中的每个值都以自己的桶结束。即使在这种情况下,当您尝试查找不在表中的键,但产生的哈希码解析为包含表中 的键的存储桶时会发生什么?您需要对值本身进行双重检查,或者表是否存在并且表示密钥存在,即使哈希代码实际上不相等!

基本上,该表使用查找键的哈希码(或者更常见的是,来自该哈希码上的某个函数的返回值)来确定要查看的桶,然后将该桶中的每个实际键与实际的查找键,以消除歧义。如果没有某种实际密钥,这将无法工作,除非:

  • 您的哈希函数保证为每个输入生成一个唯一值(使其不再是哈希函数,而是编码加密功能),
  • 你有无限数量的桶。

哈希表中没有原始数据的哈希的唯一方法是,如果哈希 数据。在这种情况下,你有一个哈希散列表。在你提到的情况下,你可以使用用户名的哈希作为密钥,映射到SHA / mcrypt / bcrypt /密码的任何哈希值。在这种情况下,哈希键,没有人关心用户名。这不会导致调整大小或其他问题,因为散列表使用的散列函数与您使用的散列函数很少有关;就哈希表而言,你给它的哈希值只是另一个值,并且有自己的哈希码, 哈希码是哈希表在内部用来查找东西的。

但是我可能会警告你不要使用哈希来表示用户名。我建议至少有一段auth数据是防碰撞的,而哈希本质上是而不是防碰撞。如果我发现你在可能的用户可见位置存储未使用的密码,我会亲自撕毁你的编程许可证。 :)也许如果你加密用户名而不是哈希呢?这有效地保证了它的独特性,如果你使用公钥加密并“忘记”私钥,它实际上就像散列一样不可逆转。漂亮的副作用是,公钥加密由于其工作原理通常有点慢。您基本上采用1024位或更大的数字并将其自身乘以数千次。所以你有一些内置的防蛮力保护。

答案 2 :(得分:0)

您也可以存储原始密钥。如果是密码,则不要将它们存储在哈希表中。

答案 3 :(得分:0)

我想这不会回答你的问题,但我想知道哈希表如何完全不知道它的条目键。当然,除非您确定永远不会发生碰撞。我没有看到在密钥作为用户名的给定示例中如何实现这一点(除非哈希表的开头非常大)。

无论哪种方式,如果我们讨论的是实际的哈希表,而不是直接访问表,我认为在不知道密钥的情况下在不同大小的表之间复制条目在逻辑上是不可能的,因为通常哈希表的大小是哈希函数的重要组成部分。