【问题标题】:How to design a hashfunction that is scalable to exactly n elements?如何设计一个可扩展到恰好 n 个元素的哈希函数?
【发布时间】:2011-03-26 03:27:14
【问题描述】:

我有一个包含 n 个字符串(人名)的列表,我想将它们存储在哈希表或类似结构中。我知道 n 的确切值,所以我想使用该事实进行 O(1) 查找,如果我必须使用链表来存储我的哈希节点,这将变得不可能。我的第一反应是使用 djb 哈希,它基本上是这样做的:

for ( i = 0; i < len; i++ )
    h = 33 * h + p[i];

要将生成的h 压缩到[0,n] 范围内,我喜欢 简单地执行h%n,但我怀疑这会导致更高的冲突概率这种方式本质上会使我的哈希无用。

那么我的问题是,如何对字符串或生成的哈希值进行哈希处理,以使n 元素在[0,n] 上提供相对均匀的分布?

【问题讨论】:

  • 嘿...所以这就是圣杯,嗯?
  • 字符串是固定为特定值还是您的意思是任何字符串的n?如果它们是固定的,那么 caf 的答案可能是最好的(迄今为止)。
  • 我有n的名字,我事先不知道名字,到底有多少要被扔给我。此外,每个名称最多将被访问n-1 次......我认为
  • 那么完美的哈希是不可能的(因为数据是未知的)。

标签: c hash string


【解决方案1】:

只知道n 是不够的。将项目分配到存储桶是项目本身的函数,因此,如果您想要一个完美的哈希函数(每个存储桶一个项目),您需要知道数据。

无论如何,如果您将元素的数量限制为已知的n,那么您在技术上已经是 O(1) 查找。上限将基于常量n。即使对于非哈希解决方案也是如此。

您最好的选择可能是只使用您拥有的哈希函数,并将每个桶作为碰撞项目的链接列表。即使哈希不够完美,您仍然可以大大减少所花费的时间。

只有当哈希完全不完美时(所有n元素都放在一个桶中)才会和普通链表一样糟糕。

如果您事先不知道数据,那么完美的哈希是不可能的。当然,除非您使用 h 本身作为哈希键而不是 h%n,但这会占用大量存储空间:-)

我的建议是使用链表路由进行足够好的哈希。我不怀疑您可以根据人群中人名中字母的相对频率来制作更好的哈希函数,但即使您拥有的哈希(对于具有相同频率的所有字母而言是理想的)也应该足够了。

而且,不管怎样,如果你开始依赖频率并且你从那些似乎不使用元音的国家(比如波斯尼亚a)涌入了很多人,你最终会有更多的碰撞。

但请记住,这实际上取决于您使用的 n

如果n 足够小,您甚至可以对未排序的数组进行顺序搜索。我假设您的 n 在这里足够大,以至于您已经确定(或平衡二叉树)不会给您足够的性能。

一个恰当的例子:我们有一些代码可以搜索问题记录以查找离开 cmets 的人员的姓名(这样我们就可以确定团队中最后一个回复的成员)。我们团队中只有大约 10 名左右的成员,所以我们只是对他们使用顺序搜索 - 使用更快的数据结构来提高性能被认为太麻烦了。


a无意冒犯。我只记得很久以前关于克林顿授权空运元音到波斯尼亚的幽默文章。我敢肯定还有其他国家也有类似的“问题”。

【讨论】:

  • +1 好点,大 O 复杂性在这里没有发挥作用。这是一个尝试减少常量时间查找量的案例。
  • 但是我的函数的 O(1)-ness 是事后的 :( 我猜 h%n 就足够了。
  • 你总是可以在运行时生成完美的哈希函数。
【解决方案2】:

您所追求的称为完美哈希。这是一个哈希函数,其中所有的键都是提前知道的,旨在避免冲突。

gperf 程序为完美哈希生成 C 代码。

【讨论】:

  • 我会给你一个,@caf。看到特定案例的 gperf 输出使我很好地解决了我们在工作中遇到的当前特别棘手的性能问题。这是一个很好的工具。
【解决方案3】:

听起来您正在寻找perfect hash function 的实现,或者甚至是最小的完美哈希函数。根据维基百科页面,CMPH 可能 适合您的需求。免责声明:我从未使用过。

【讨论】:

    【解决方案4】:

    n字符串映射到整数1-n的最佳算法是构建一个终止状态为整数1-n的DFA。 (我相信这里有人会为此起一个花哨的名字......但最终都是DFA。)大小/速度的权衡可以通过改变你的字母大小来调整(操作字节,半字节,或偶数位)。

    【讨论】:

      猜你喜欢
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 2010-10-18
      • 2010-10-12
      • 2013-10-22
      • 1970-01-01
      • 2011-07-21
      相关资源
      最近更新 更多