【问题标题】:Memory efficient way to remove duplicate lines in a text file using C++使用 C++ 删除文本文件中重复行的内存有效方法
【发布时间】:2011-01-28 20:51:48
【问题描述】:

使用 C++ 删除大型文本文件中的重复行最节省内存的方法是什么?

让我澄清一下,我不是要代码,只是最好的方法。不保证重复的行是相邻的。我意识到针对最小内存使用进行优化的方法会导致速度变慢,但这是我的限制,因为文件太大了。

【问题讨论】:

  • 你能假设什么?例如,它们是否保证相邻?
  • 请贴出你目前写的代码。人们通常不喜欢只为您编写代码。
  • 关于什么你想要高效?文件访问?记忆? CPU 利用率。 3 人意见不一致。
  • 让我澄清一下,我不是要代码,只是最好的方法。我可以自己编写代码。不保证重复的行是相邻的。我意识到针对最小内存使用优化的方法会导致速度变慢,但这是我的限制,因为文件太大了。
  • Stefan,在我的问题中,我在内存方面指定了高效。

标签: c++ file file-io io


【解决方案1】:

为什么不直接咨询Knuth, Sorting and Searching?这将为您提供做出平衡决定的良好背景。

【讨论】:

    【解决方案2】:

    简单的蛮力解决方案(非常少的内存消耗): 做一个 n^2 遍历文件并删除重复的行。速度:O(n^2),内存:常数

    快速(但很差,内存消耗): Stefan Kendall 的解决方案:对每条线进行哈希处理,将它们存储在某种地图中,然后删除已经存在的线。速度:O(n),内存:O(n)

    如果您愿意牺牲文件顺序(我假设不会,但我会添加它): 您可以对行进行排序,然后通过删除重复项。速度:O(n*log(n)),内存:常数

    编辑: 如果您不喜欢对文件内容进行排序或尝试维护唯一哈希但可以处理 O(n) 内存使用的想法:您可以使用它的 32 位或 64 位位置标记(取决于文件的大小)识别每一行并排序文件位置而不是文件内容。

    编辑#2:警告:不同长度的内存排序行比说一个整数数组更难...实际上,考虑内存在合并步骤中如何移动和移动,我第二次猜测我在 n*log(n) 中对文件进行排序的能力

    【讨论】:

    • 从您的回答中不清楚,如何通过使用恒定的内存量来对大小为 N 的文件进行排序。
    【解决方案3】:

    我会散列每一行,然后寻找具有非唯一散列的行并单独比较它们(或以缓冲的方式)。这适用于重复发生率相对较低的文件。

    当您使用哈希时,您可以将使用的内存设置为一个常数(即,您可以有一个只有 256 个插槽或更大的小哈希表。在任何情况下,内存的数量都可以限制为任何常量。)表中的值是具有该哈希的行的偏移​​量。所以你只需要 line_count*sizeof(int) 加上一个常量来维护哈希表。

    更简单(但慢得多)的是扫描整个文件的每一行。但我更喜欢第一种选择。这是内存效率最高的选项。您只需要存储 2 个偏移量和 2 个字节即可进行比较。

    【讨论】:

    • 如果文件包含比哈希和短的行怎么办?散列应该只用于行长的文件(你在开始之前就知道了)。我想唯一通用的方法是排序(O(nlog(n))然后扫描(O(n)),即O(nlog(n))。
    • @sergey 您的排序扫描方法不会保留原始行顺序吗?
    【解决方案4】:

    尽量减少内存使用:

    如果您有无限(或非常快)的磁盘 i/o,您可以将每一行写入其自己的文件,文件名是哈希值 + 一些指示顺序的标识符(或无顺序,如果顺序无关紧要)。通过这种方式,您可以将文件系统用作扩展内存。这应该比为每一行重新扫描整个文件要快得多。

    作为下文所述的补充,如果您期望较高的重复率,您可以在内存和文件中保持一定的哈希阈值。这将为高重复率提供更好的结果。由于文件太大,我怀疑n^2 在处理时间上是否可以接受。我的解决方案是处理速度方面的O(n) 和内存方面的O(1)。但是,在运行时所需的磁盘空间中,它是 O(n),这是其他解决方案所没有的。

    听起来您可能在各种规格的有限硬件上运行,因此您需要测试一些重复删除算法和配置文件,然后再决定哪种最适合长期实施。

    【讨论】:

    • 如果您的哈希算法又快又笨(高冲突率),请运行 KMP 或其他一些比线性更快的字符串匹配算法。
    【解决方案5】:

    您可以使用 I/O 高效排序(如 unix 排序命令),然后逐行读取文件,将每一行与之前读取的行进行比较。如果两者相等,则不输出任何内容,如果它们不输出该行。

    这样算法使用的内存量是恒定的。

    【讨论】:

    • 您不能将 unix 命令视为算法之外。这是过程的一部分,因此必须计算在内。鉴于它必须存储项目的排序顺序,它必须使用线性内存。
    • 我建议使用类似 unix 排序命令的东西。事实上,可以实现 I/O 高效排序以在内存使用量恒定的情况下运行:将文件分成大小为 c 的块。读入每个大小为 c 的块并对其进行排序。将结果输出到临时文件。使用大小为 c 的读取缓冲区合并已排序的块。有关外部(I/O 高效排序)的更多信息,请参阅en.wikipedia.org/wiki/External_sorting,以及 Knuth 书。
    • 我的印象是可以使用任何类型的内存(外部或 RAM)。如果他可以使用磁盘空间,那么你的方法绝对可行。
    • 鉴于问题陈述所暗示的硬盘空间使用与输入大小成线性关系(例如,在最坏的情况下,输出大小 = 输入大小),使用外部合并排序将磁盘空间使用量不会发生巨大变化。
    猜你喜欢
    • 2022-08-21
    • 2010-10-06
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多