有效地在文件中构建一组唯一行,而无需在集中存储实际行
Building a set of unique lines in a file efficiently, without storing actual lines in the set
最近我试图解决以下问题:
我有一个非常大的文件,包含长行,我需要查找并打印出其中所有独特的行。
我不想使用存储实际行的映射或集合,因为文件非常大且行很长,因此这将导致 O(N) 空间复杂性和较差的常量(其中 N 是行数)。最好是,我宁愿生成一个集合,存储指向文件中唯一行的指针。显然,这种指针的大小(我相信 64 位机器上的 8 个字节)通常比内存中的行大小(我相信每个字符 1 个字节)小得多。虽然空间复杂度仍然是O(N),但现在常数要好得多。使用此实现,文件永远不需要完全加载到内存中。
现在,假设我将逐行浏览文件,检查唯一性。为了查看它是否已经在集合中,我可以与到目前为止集合指向的所有线条进行比较,逐个字符进行比较。这给出了 O(N^2*L) 复杂性,L 是一条线的平均长度。当不关心将整行存储在集合中时,由于散列,可以实现 O(N*L) 复杂度。现在,当使用一组指针代替(以减少空间需求)时,我如何仍然可以实现这一点?有没有一种巧妙的方法可以做到这一点?我唯一能想到的就是这种方法:
- 对句子进行哈希处理。将哈希值存储到 map(或者实际上:unordered_multimap无序的获取哈希映射样式,在"错误匹配"的情况下可以插入多键作为双键)。
- 对于每个新句子:检查其哈希值是否已在映射中。如果没有,请添加它。如果是,请逐个字符比较完整的句子(新句子和无序列图中具有相同哈希的句子),以确保没有"错误匹配"。如果是"错误匹配",请仍然添加它。
这是正确的方法吗?或者有更好的方法可以做到这一点吗?欢迎所有建议!
我可以使用一些聪明的"比较对象"(或类似的东西,我还不太了解)来对每个 unordered_map::find() 调用时完全自动化的现有句子进行检查?
您的解决方案对我来说看起来不错,因为您存储的是 O(唯一行)哈希而不是 N,所以这是一个下限。
由于您逐行扫描文件,因此不妨对文件进行排序。现在,重复的行将是连续的,您只需检查前一行的哈希值。此方法使用 O(1) 空间,但您必须先对文件进行排序。
正如@saadtaame的回答所说,你的空间实际上是O(唯一行) - 根据您的用例,这可能是可以接受的,也可能是不可接受的。
虽然散列当然有其优点,但它可能会有很多冲突问题 - 如果你不能有误报,那么除非你真的保留行的内容以供检查,否则它是不行的。
您描述的解决方案是维护基于哈希的集。这显然是最直接的事情,是的,它需要维护内存中的所有唯一行。不过,这可能是也可能不是问题。该解决方案也是最容易实现的 - 您正在尝试做的正是(基于哈希的)集合的任何实现都会做的事情。您可以只使用 std::unordered_set
,并将每一行添加到集合中。
由于我们正在抛出想法,您也可以使用 trie 作为集合的替代品。您可能会节省一些空间,但它仍然是 O(唯一行)。
如果文件中没有可以利用的特殊结构,那么最终要对行进行哈希处理。这将比实际将文件中的每一行与其他行进行比较要快几个数量级。
如果你的实际实现仍然太慢,你可以将哈希限制在每行的第一部分。这将产生更多的误报,但假设大多数行在前几个单词中已经偏离,它将显着加快文件处理速度(特别是,如果您是 I/O 绑定)。
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 为什么C++不使用集中存储类型信息以实现高效的 RTTI
- 如何在位集中存储随机生成的无符号整数
- 有效地在文件中构建一组唯一行,而无需在集中存储实际行
- 获取存储在C++集中的结构中的值