在java中为字符串构造唯一的数字

时间:2010-06-14 13:11:32

标签: java key checksum hashcode message-digest

我们要求在文件中读/写超过1000万个字符串。此外,我们不希望文件中有重复项。由于字符串在读取后会立即刷新到文件中,因此我们不会将其保留在内存中。

我们不能使用哈希码,因为哈希码中的冲突导致我们可能会错过一个字符串作为重复。 我在谷歌搜索中找到的另外两种方法:

1.使用消息摘要算法(如MD5) - 但计算和存储的成本可能过高。

2.使用校验和算法。 [我不确定这是否会产生一个字符串的唯一键 - 有人可以确认]

是否有任何其他方法可用。 感谢。

6 个答案:

答案 0 :(得分:7)

如果您对显微镜冲突风险感到满意,可以按照建议使用某些哈希函数(如MD5),并依赖哈希值。

另一种可能具有更大内存占用的替代方法是将已经遇到的字符串存储在trie(一种特殊类型的树)中。


更新:另一种选择是使用Bloom filter。然而,这仍然依赖于散列,但可以调整为具有任意小的碰撞概率。

答案 1 :(得分:6)

在内存中存储1000万个字符串确实很多,所以我理解将其立即写入文件而不是存储在例如文件中的原因。首先是TreeSet<String>,但 你想要存储你要比较的1000万个唯一数字键吗?如果你想保持它唯一数字(它比字母更小的基数/基数),你不能使密钥短于字符串本身,所以你不会保存任何记忆。或者像GZIP那样最高的数据压缩,但这只会增加很多开销。 MD5也不合适,因为两个不同的字符串可以产生相同的哈希值。

我真的没有比使用体面的RDBMS(SQL数据库)更好的解决方案,其中您将列设置为UNIQUE并相应地处理约束违规。 RDBMS针对此类任务进行了高度优化。

如果你真的不能考虑数据库,那么你需要在写/刷新之前重新读取任何现有条目的文件。也许不是很快,但肯定有记忆效率。

答案 2 :(得分:1)

无法创建一个能够为字符串生成唯一键的函数,该字符串比该字符串短。
有数据结构可以解决您的任务。如果数据足够大,B树可能适合。根据输入的性质,可能会有更有效的方法。

答案 3 :(得分:1)

可靠地删除重复项与排序文件一样困难。正如另一个答案所表明的那样,没有保证精确检测重复的方法而不保留每个字符串在内存中的完整副本,这似乎正是你想要避免的。

您可以保留内存或磁盘上的哈希码索引,并使用这些索引从文件存储中检索实际字符串以进行比较,但这实际上会复制数据库能够为您执行的操作。

另一种方法是在文件完成后对文件进行后处理。 UNIX sort命令非常适合大文件(How could the UNIX sort command sort a very large file?),所以我希望标准的UNIX命令行方法能够合理地工作:

    sort my-file-of-strings.txt | uniq > my-filtered-file-of-strings.txt

(请注意,在传递给uniq以删除重复项之前,必须先对文件进行排序。)

如果您还没有这些工具(或等效工具)可用,那么您可以自己尝试实现外部合并排序的某种变体。

答案 4 :(得分:0)

如果字符串来自固定的可能字符串池(N),则可以使用最小完美散列来创建数组0 ... N-1。由完美散列函数确定的槽中的零意味着到目前为止还没有看到该字符串。

否则,唯一有效的正确方法是在很多内存之外,目前建议的解决方案是在决定将字符串写入之前重新读取文件。

您可以通过文件的内存映射部分尽可能高效地完成此操作。

答案 5 :(得分:0)

我认为最好的解决方案是 - 正如其他人已经建议的那样 - 使用数据库。

如果由于某种原因您无法使用数据库,您仍然可以使用哈希码。肯定会有碰撞。只需添加一些代码,以便在检测到重复的哈希码时,程序会检查文件以确定它是真正的重复还是冲突。