【问题标题】:Univocal hash function for a string 76 chars long76 个字符长的字符串的单义哈希函数
【发布时间】:2011-08-17 18:29:08
【问题描述】:

这是我的问题(我正在用 C 编程):

我有一些包含 DNA 序列的巨大文本文件(每个文件大约有 6500 万行,大小约为 4~5 GB)。在这些文件中有很多重复项(还不知道有多少,但应该有数百万个),我想在输出中返回一个只有不同值的文件。每个字符串都有一个相关的质量值,所以如果我有 5 个具有不同质量值的相等字符串,我将保留最好的一个并丢弃其他 4 个。

尽我所能减少内存需求并提高速度效率是至关重要的。 我的想法是使用哈希函数创建一个 JudyHS 数组,以便将字符串 DNA 序列(长 76 个字母,有 7 个可能的字符)转换为整数,以减少内存使用量(4 或 8 个字节,而不是 76 个字节数以百万计的条目应该是一个相当大的成就)。这样我就可以使用整数作为索引并只存储该索引的最佳质量值。问题是我找不到一个 UNIVOCALLY 定义这么长的字符串并产生一个可以存储在整数甚至 long long 内的值的哈希函数!

我对哈希函数的第一个想法类似于 Java 中的默认字符串哈希函数:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],但我可以获得最大值 8,52*10^59.. 太大了。 做同样的事情并将其存储在双重中怎么样?计算会变得慢很多吗? 请注意,我想要一种 UNIVOCALLY 定义字符串的方法,避免碰撞(或者至少它们应该非常罕见,因为我必须在每次碰撞时访问磁盘,这是一个相当昂贵的操作......)

【问题讨论】:

  • 不回答您的问题,但希望能解决您的问题:prefix tree 是否适合紧凑地保存您的数据?
  • 感谢您的回答,但据我了解,这实际上就是 Judy 数组的含义,而且无论如何,我读过声称它对他们来说更节省空间,所以我想试一试

标签: c string hash dna-sequence


【解决方案1】:

您有 7^76 个可能的 DNA 序列,并希望将它们映射到 2^32 个散列而不发生冲突?不可能。

您至少需要 log2(7^76) = 214 位才能做到这一点,大约 27 个字节。

我建议您坚持使用 CRC32 或 md5,而不是再次发明新轮子。

【讨论】:

  • 有什么算法可以让我在这 214 位中编码这 7^76 个可能的值吗?
  • @Alex:如果没有特殊的长整数运算,我会使用 7^11 组,它可以用小于 32 位编码,并使用 7 个 32 位整数。假设序列中的值在 0..6 范围内:对于每组 11 个值,计算 (((v0*7 + v1)*7 + v2)*7 +v3)*7 ... + v10.这将小于 1977326743 并适合 32 位整数。计算 7 组,将最后一组的 v10 设置为零。
  • 但我宁愿使用简单的哈希函数和足够长的密钥。正如 Thomas 所写,仅使用 64 位散列将不太可能发生冲突。查找en.wikipedia.org/wiki/Birthday_problem:在您的情况下,表中发生冲突的概率小于 1/1000。
  • 冲突的问题是有丢弃一些不应该丢弃的值的风险,为了效率我不允许丢弃一个字符串。我想我会实现你关于 7 个组的想法,并添加选项以使用 Thomas 更有效(但有点不安全)的建议。谢谢你们!
  • 请注意,每次访问字符串时发生冲突的概率不是 1/1000,而是在 65M 条目的整个表中。或者反过来说:如果你有 1000 个 5 GByte 的表,生成 5 TByte 的数据,很可能只有其中一个表会发生冲突,而其他 999 个表不会发生冲突。跨度>
【解决方案2】:

获得 N 个元素的无冲突散列函数的“简单”方法是使用良好的混合函数(例如,加密散列函数)并截断大小,以便哈希结果存在于大小至少为 N2 的空间中。在这里,您有 6500 万行——这适合 26 位(226 接近 6500 万)所以 52 位“应该足够了”。

您可以尝试使用快速加密散列函数,甚至是“损坏”的散列函数,因为这不是与安全相关的问题。 MD4、MD5、SHA-1...然后将结果截断为第一个(或最后一个)64 位,并将其存储为 64 位整数类型。您的 6500 万行中可能不会发生任何冲突;如果你得到一些,它们将非常罕见。

对于哈希函数的优化 C 实现,查找 sphlib。使用提供的 sph_dec64le() 函数将 8 位序列“解码”为 64 位无符号整数值。

【讨论】:

  • 问题是,每次我遇到冲突时,我都需要区分它是由重复(因此丢弃)还是由不同的值(并保存)引起的,而没有存储原始字符串在哈希表中。如果有某种算法可以让我做到这一点(但我无法想象如何),那么碰撞的数量几乎是无关紧要的......
猜你喜欢
  • 1970-01-01
  • 2015-03-09
  • 2015-06-22
相关资源
最近更新 更多