【发布时间】:2023-04-01 23:58:01
【问题描述】:
我实现了一个自定义的 HashMap 类(在 C++ 中,但没关系)。实现很简单 -
- 一个大数组包含指向项目的指针。
- 每个项目都包含键值对和指向项目的指针(在发生键冲突时形成链表)。
- 我还为它实现了一个迭代器。
我对迭代器进行递增/递减的实现效率不是很高。从当前位置开始,迭代器扫描哈希数组以查找下一个非空条目。当地图人口稀少时(这将是我的用例),这是非常低效的。
谁能建议一个更快的实现,而不影响插入和查找等其他操作的复杂性?我的主要用例是查找,次要是插入。甚至不需要迭代,我只是为了学习而了解这一点。
PS:为什么我实现了一个自定义类?因为我需要找到具有一定容错性的字符串,而我看到的现成哈希映射只提供完全匹配。
编辑:为了澄清,我说的是增加/减少已经获得的迭代器。是的,这主要是为了遍历整个地图。
在我的例子中,字符串(键)中的错误是由 OCR 错误引起的。所以我不能使用用于检测打字错误的错误处理技术。拳字出错的几率和上一字差不多。
另外,我的键总是字符串,确切地说是一个词。条目数将少于 5000。所以 2^16 的哈希表大小对我来说就足够了。即使它仍然会人口稀少,但没关系。
我的哈希函数:
哈希码大小为 16 位。
字长的前 5 位。 ==> 最大可能的密钥长度 = 32。考虑到密钥是单个单词,这是合理的。
字符代码总和的最后 11 位。我只存储英文字母字符,不需要区分大小写。所以 26 个代码就足够了,从 0 到 25。所以一个 32 'z' = 25 * 32 = 800 的键。正好在 2^11 之内。如果将来需要,我什至可以添加区分大小写的功能。
现在,当您将包含错误的密钥与正确的密钥进行比较时, 用“你好”说“地狱” 1. 密钥长度大致相同 2. 它们的字符总和会因丢弃/添加/扭曲字符的总和而有所不同。
在哈希码中,由于前 5 位是长度,整个表对于每个可能的键长度都有固定的部分。所有部分的大小相同。第一部分存储长度为 1 的键,第二部分存储长度为 2 的键,依此类推。
现在 'hello' 存储在第 5 部分,因为长度为 5。'当我们尝试查找 'hello' 时, 'hello' 的哈希码 = (length - 1) (sum of chars) = (4) (7 + 4 + 11 + 11 + 14) = (4) (47) = (00100)(00000101111)
类似地,'helo' 的哈希码 = (3)(36) = (00011)(00000100100)
- 我们跳到它的桶里,却找不到它。
- 所以我们尝试检查一个扭曲的字符。这不会改变长度,但会将字符的总和最大 -25 更改为 +25。所以我们从向后的 25 个位置搜索到向前的 25 个位置。即,我们在同一部分检查从 (36-25) 到 (36+25) 的总和部分。我们不会找到它。
- 我们检查其他字符错误。这意味着正确的字符串将只包含 3 个字符。所以我们进入第三部分。现在由于额外的字符,字符的总和最多会增加 25,它必须得到补偿。因此,在第三部分中搜索适当的 25 个位置 (36 - 0) 到 (36 - 25)。我们还是没有找到。
- 现在我们考虑缺少字符的情况。所以原始字符串将包含 5 个字符。而哈希码的第二部分,即原始字符串中的字符之和,会多出 0 到 25 倍。所以我们在第 5 部分搜索相应的 25 个桶,(36 + 0) 到 (36 + 25)。现在由于 47('hello' 的总和部分)在这个范围内,我们将找到哈希码的匹配项。 Ans 我们也知道这个匹配是由于缺少字符。因此,我们比较允许 1 个缺失字符容差的键。我们得到了一场比赛!
实际上,这已被实施以允许键中出现多个错误。 它还可以优化为第一部分仅使用 25 个位置(因为它只有一个字符)等等。 此外,检查 25 个位置似乎有点过分,因为我们已经知道键的最大和最小字符。但是如果出现多个错误,它就会变得复杂。
【问题讨论】:
-
我不明白,当你试图找一个值的时候,你不应该马上去给定key的数组中保存的第一个
Item,然后遍历一个链表吗?如果你必须遍历整个数组,那么要么你的数组太小,要么你的散列函数不是很好(这种情况发生的唯一方法是如果有 tons 的冲突)。跨度> -
@Jared 我认为(很可能是错误的)他说的是迭代整个哈希映射,而不仅仅是一个冲突链。很高兴知道为了更清楚,我同意。
-
你是说你想要像
"hello"和"hwllo"这样的东西映射到相同的哈希值(因为它们是相似的——注意'e'和'w'很容易不小心根据他们在 QWERTY 键盘上的位置相互键入)。因此,您想要快速查找本质上对相似字符串进行分组?因为如果您说查看每个字符串并进行比较(并找到最接近的字符串),那么您并没有描述任何可以远程解释为哈希表的内容。 -
@Jared 我已经更新了这个问题并进行了澄清。我想改进迭代整个哈希图。我不希望“hello”和“hwllo”具有相同的哈希值,但是当存储“hello”并尝试查找“hwllo”时,我应该能够有效地到达“hello”。这部分已经实现,现在在问题中进行了更新。
-
@WhozCraig 是的,你的想法是对的。请查看更新后的问题以了解详细实施情况。
标签: java c++ data-structures iterator hashmap