用什么算法删除重复项?

时间:2011-11-03 13:27:46

标签: algorithm duplicates

想象一下,我们有一些文件,例如“A.txt”。我们知道 有些重复元素。 “A.txt”非常大,比内存大十倍,可能大约50GB。有时候,B的大小大约等于A的大小,有时它会比A的大小倍。 让它有这样的结构:

a 1
b 2
c 445
a 1

我们需要获取文件“B.txt”,它不会有这样的副本。例如,它应该是这样的:

a 1
b 2
c 445

我想到了复制A并执行B的算法,然后在B中获取第一个字符串,并查找彼此,如果发现相同,则删除重复项。然后采取第二个字符串等

但我认为方式太慢了。我可以使用什么?

A 不是数据库!请不要SQL。

对不起,没说,排序还可以。

虽然可以对它进行排序,但是如果它无法排序呢?

3 个答案:

答案 0 :(得分:6)

一种解决方案是对文件进行排序,然后一次将一行复制到新文件中,过滤掉连续的重复项。

然后问题就变成了:你如何对一个太大而不适合内存的文件进行排序?

这是how Unix sort does it

另见this question

答案 1 :(得分:4)

假设您可以将文件的1/k放入内存中,并且仍然有工作数据结构的空间。整个文件可以在k或更少的传递中处理,如下所示,这有可能比根据行长度和排序算法常量对整个文件进行排序要快得多。排序平均值O(n ln n),以下流程为O(k n)最差情况。例如,如果行平均为10个字符,并且有n = 5G行,ln(n) ~ 22.3。此外,如果输出文件B远小于输入文件A,则该过程可能只需要一到两次。

流程:

  1. 为输入缓冲区I分配几兆字节,为结果缓冲区R分配几千兆字节,为哈希表H分配一千兆字节左右。打开输入文件F和输出文件O。
  2. 重复:从F填写并通过步骤3将其处理为R.
  3. 对于I中的每一行L,检查L是否已经在H和R中。如果是,则继续下一个L,否则将L添加到R并将其哈希添加到H.
  4. 当R已满时,用M个条目表示,将其写入O.然后从F中重复填充I,如步骤3中的重复数据删除,并写入O.在EOF(F)转到5.
  5. 重复(使用旧O作为输入F和输出新O):从F读取M行并复制到O.然后按步骤2和3加载R和H,并使用重复数据删除复制到EOF(F)像之前一样。将M设置为每个O文件开头的新的非重复行数。
  6. 请注意,在每次传递之后,O的前M行不包含重复项,并且这些M行中没有一行在O的其余部分中重复。因此,处理原始文件的至少1/k'每次通过,因此处理最多需要k次传递。

    更新1 不应在已处理的前导行中重复写出和读回,而应使用单独的输出文件P,在每次传递结束时附加过程缓冲区R. 。当结果文件B几乎与A一样大时,这会将读取和写入量减少k/2,或者当B远小于A时,减少一些因子;但在任何情况下都不会增加I / O的数量。

答案 2 :(得分:2)

你基本上必须建立一个可搜索的结果集(如果语言提醒你数据库技术,这不是偶然的,无论你多么讨厌数据库处理与你相同的问题这一事实)。 / p>

其中一种可能的高效数据结构是排序范围(可实现为某种树)或哈希表。因此,在处理文件时,您可以有效地将每条记录插入到结果集中,然后在该阶段检查结果是否已存在。完成后,您将获得一组简化的独特记录。

您的结果集还可以将某种类型的引用存储到任何一个原始记录中,而不是复制实际记录。这取决于记录是否足够大,以使其成为更有效的解决方案。

或者您只需在原始数据中添加标记,无论是否包含该记录。

(另外考虑使用像NetCDF这样的高效存储格式来处理二进制数据,因为文本表示的访问和处理速度要慢得多。)