有效地在文件中构建一组唯一行,而无需在集中存储实际行

Building a set of unique lines in a file efficiently, without storing actual lines in the set

本文关键字:存储 集中 一组 构建 文件 有效地 唯一      更新时间:2023-10-16

最近我试图解决以下问题:

我有一个非常大的文件,包含长行,我需要查找并打印出其中所有独特的行。

我不想使用存储实际行的映射或集合,因为文件非常大且行很长,因此这将导致 O(N) 空间复杂性和较差的常量(其中 N 是行数)。最好是,我宁愿生成一个集合,存储指向文件中唯一行的指针。显然,这种指针的大小(我相信 64 位机器上的 8 个字节)通常比内存中的行大小(我相信每个字符 1 个字节)小得多。虽然空间复杂度仍然是O(N),但现在常数要好得多。使用此实现,文件永远不需要完全加载到内存中。

现在,假设我将逐行浏览文件,检查唯一性。为了查看它是否已经在集合中,我可以与到目前为止集合指向的所有线条进行比较,逐个字符进行比较。这给出了 O(N^2*L) 复杂性,L 是一条线的平均长度。当不关心将整行存储在集合中时,由于散列,可以实现 O(N*L) 复杂度。现在,当使用一组指针代替(以减少空间需求)时,我如何仍然可以实现这一点?有没有一种巧妙的方法可以做到这一点?我唯一能想到的就是这种方法:

  1. 对句子进行哈希处理。将哈希值存储到 map(或者实际上:unordered_multimap无序的获取哈希映射样式,在"错误匹配"的情况下可以插入多键作为双键)。
  2. 对于每个新句子:检查其哈希值是否已在映射中。如果没有,请添加它。如果是,请逐个字符比较完整的句子(新句子和无序列图中具有相同哈希的句子),以确保没有"错误匹配"。如果是"错误匹配",请仍然添加它。

这是正确的方法吗?或者有更好的方法可以做到这一点吗?欢迎所有建议!

我可以使用一些聪明的"比较对象"(或类似的东西,我还不太了解)来对每个 unordered_map::find() 调用时完全自动化的现有句子进行检查?

您的解决方案对我来说看起来不错,因为您存储的是 O(唯一行)哈希而不是 N,所以这是一个下限。

由于您逐行扫描文件,因此不妨对文件进行排序。现在,重复的行将是连续的,您只需检查前一行的哈希值。此方法使用 O(1) 空间,但您必须先对文件进行排序。

正如@saadtaame的回答所说,你的空间实际上是O(唯一行) - 根据您的用例,这可能是可以接受的,也可能是不可接受的。

虽然散列当然有其优点,但它可能会有很多冲突问题 - 如果你不能有误报,那么除非你真的保留行的内容以供检查,否则它是不行的。

您描述的解决方案是维护基于哈希的集。这显然是最直接的事情,是的,它需要维护内存中的所有唯一行。不过,这可能是也可能不是问题。该解决方案也是最容易实现的 - 您正在尝试做的正是(基于哈希的)集合的任何实现都会做的事情。您可以只使用 std::unordered_set ,并将每一行添加到集合中。

由于我们正在抛出想法,您也可以使用 trie 作为集合的替代品。您可能会节省一些空间,但它仍然是 O(唯一行)。

如果文件中没有可以利用的特殊结构,那么最终要对行进行哈希处理。这将比实际将文件中的每一行与其他行进行比较要快几个数量级。

如果你的实际实现仍然太慢,你可以将哈希限制在每行的第一部分。这将产生更多的误报,但假设大多数行在前几个单词中已经偏离,它将显着加快文件处理速度(特别是,如果您是 I/O 绑定)。