【问题标题】:Find common elements from two very large Arrays从两个非常大的数组中查找共同元素
【发布时间】:2012-01-23 14:51:15
【问题描述】:

有两个整数数组,每个都在非常大的文件中(每个的大小都大于 RAM)。如何在线性时间内找到数组中的共同元素。

我找不到解决这个问题的好方法。有任何想法吗?

【问题讨论】:

  • 它们排序了吗?
  • 这有很大的不同——如果它们是 16 位整数,那将是一个非常简单的解决方案。
  • @Groo: 2^16 小到足以使计数排序可行。
  • @Fanael:没错,我想到了一个位数组来仅存储存在标志,但现在我已经完成了计算,它仍然很大(4096Mb/8=512Mb)。如果需要 O(n),现在我能想到的只是一个基于磁盘的哈希表。
  • 是的。我也在考虑将位数组作为标志,我认为 512 MB 不是很多。这是一个不错的解决方案,而且速度很快。让我们看看其他人怎么说。

标签: c++ algorithm


【解决方案1】:

一个文件的一次传递构建一个位图(如果整数范围对于内存中的位图来说太大,则为 Bloom filter)。

对另一个文件进行一次遍历查找重复项(如果使用 Bloom 过滤器,则为候选项)。

如果您使用 Bloom 过滤器,则结果是概率性的。新的 pass 可以减少误报(布隆过滤器没有误报)。

【讨论】:

  • 对于 4 字节整数,您不需要 Bloom 过滤器,只需 0.5GB 内存。
  • 我猜这是可行的,.听起来是个不错的解决方案。谢谢。
【解决方案2】:

假设整数大小为 4 个字节。 现在我们最多可以有 2^32 个整数,即我可以有一个 2^32 位(512 MB)的位向量来表示每个位代表 1 个整数的所有整数。 1. 用全零初始化这个向量 2. 现在遍历一个文件,如果找到一个整数,则将该向量中的位设置为 1。 3. 现在浏览其他文件并在位向量中查找任何设置位。

时间复杂度 O(n+m) 空间复杂度 512 MB

【讨论】:

  • 只有当多次出现可以被视为单个输出时才会起作用。在我看来很棒。
  • 2^32 位是 512Mb,不是吗?
  • 这个和上面的方案差不多'
  • @blaze,2^32 是 512Mbits 即 64 MBytes
  • @Manan 2^32 位 = 4294967296 位 = 536870912 字节 = 512 * 1024 * 1024 = 512 兆字节。 32 位系统可以寻址 4Gb 的内存而不是 512Mb 不是很好吗?
【解决方案3】:

您显然可以使用哈希表来查找具有 O(n) 时间复杂度的常见元素。

首先,您需要使用第一个数组创建一个哈希表,然后使用该哈希表比较第二个数组。

【讨论】:

  • 列表的大小比 RAM 大.. 您的哈希表不会完全保存任何数组.. :/
  • 请详细说明...你的意思
  • 基于文件的哈希表只是一个哈希表,该表存储在文件中而不是内存中。
  • ok.. 如果哈希表在文件中。它会起作用的。但听起来不是一个非常有效的方法。
  • @KshitijBanerjee 但它是 O(n),并且是确定性的 - 与 Bloom Filter 方法不同。
【解决方案4】:

假设有足够的 RAM 可以容纳任一给定文件数组 (FA) 的 5% 的哈希值。

所以,我可以将文件数组(FA1 和 FA2)分成 20 个块,每个块 - 比如说 MOD 20 个内容。我们得到 FA1(0)....FA1(19) 和 FA2(0)......FA2(19)。这可以在线性时间内完成。

在内存中散列 FA1(0) 并将 FA2(0) 的内容与此散列进行比较。散列和检查是否存在是常数时间操作。

销毁此哈希并重复 FA1(1)...FA1(19)。这也是线性的。所以,整个操作是线性的。

【讨论】:

    【解决方案5】:

    假设您正在谈论具有相同大小的整数,并以二进制模式写入文件,您首先对 2 个文件进行排序(使用快速排序,但读取和写入文件“偏移量”)。 然后你只需要从两个文件的开头移动,并检查匹配,如果你有一个匹配,将输出写入另一个文件(假设你不能也将结果存储在内存中)并继续移动文件直到EOF。

    【讨论】:

    • 按要求排序不是 O(n)。
    • 对固定大小的整数进行排序实际上是 O(n):基数排序。但是处理比内存大的文件可能是个问题。
    【解决方案6】:

    对文件进行排序。使用固定长度的整数,它可以在 O(n) 时间内完成:

    1. 获取文件的某些部分,使用基数排序对其进行排序,写入临时文件。重复直到所有数据完成。这部分是O(n)
    2. 合并排序的部分。这也是 O(n)。您甚至可以跳过重复的数字。

    在已排序的文件中找到整数的公共子集:比较数字,如果相等则将其写下来,然后在具有较小数字的文件上前移一个数字。这是 O(n)。

    所有操作都是O(n),最终算法也是O(n)。

    编辑:如果您有足够的内存用于位图,位图方法会快得多。此方法适用于任何固定大小的整数,例如 64 位。大小为 2^31 Mb 的位图至少在几年内都不实用:)

    【讨论】:

      猜你喜欢
      • 2020-03-26
      • 2015-07-20
      • 1970-01-01
      • 2021-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      相关资源
      最近更新 更多