Algorithm 找到两个集合之间的重复项的有效方法是什么?

Algorithm 找到两个集合之间的重复项的有效方法是什么?,algorithm,set,Algorithm,Set,我设置了A和B 集合A有1亿个数字(每个数字为64位) 集合B有1亿个数字(每个数字为64位) 两套尺寸相同 数据都是随机的,没有排序 您建议使用什么算法来查找两个集合之间的重复数 (我可以利用大约4G内存和100~200GB磁盘空间) 提前感谢您。64位=8字节。2*8*100000000字节=1.6GB=>您可以将数字保存在RAM中(节点结构可能需要两倍的数字…)。我会选择平衡二叉树(只需在wiki上搜索AVL、AB…树)。只需将数字从一个集合添加到一棵树,从另一个集合添加到另一棵树,然后进

我设置了A和B

集合A有1亿个数字(每个数字为64位)

集合B有1亿个数字(每个数字为64位)

两套尺寸相同

数据都是随机的,没有排序

您建议使用什么算法来查找两个集合之间的重复数

(我可以利用大约4G内存和100~200GB磁盘空间)


提前感谢您。

64位=8字节。2*8*100000000字节=1.6GB=>您可以将数字保存在RAM中(节点结构可能需要两倍的数字…)。我会选择平衡二叉树(只需在wiki上搜索AVL、AB…树)。只需将数字从一个集合添加到一棵树,从另一个集合添加到另一棵树,然后进行交叉

您可能只需要对两个数组进行排序并使它们相交。这应该是最简单的解决办法


若您无法处理内存中的所有数字,请使用数据库(MySQL、PostgreSQL…)。两个排序表和交叉点。它应该非常快速,最重要的是易于实现。

64位=8字节。2*8*100000000字节=1.6GB=>您可以将数字保存在RAM中(节点结构可能需要两倍的数字…)。我会选择平衡二叉树(只需在wiki上搜索AVL、AB…树)。只需将数字从一个集合添加到一棵树,从另一个集合添加到另一棵树,然后进行交叉

您可能只需要对两个数组进行排序并使它们相交。这应该是最简单的解决办法


若您无法处理内存中的所有数字,请使用数据库(MySQL、PostgreSQL…)。两个排序表和交叉点。它应该非常快速,而且最重要的是易于实现。

因为整个数据集都可以(轻松地)装入RAM,所以您不需要对其进行任何巧妙的排序,也不需要使用磁盘空间(除了首先加载数据之外)

我假设每个元素在每个列表中最多只能存在一次

哑(蛮力)法,O(n^2):

预排序方法:(2*n*log(n)+n),so(n*log(n))

我建议采用前者,但采用并行处理。很容易将外部循环分解成块,在处理器/工作站之间进行分割。后者也可以进行某种程度的并行化(同时执行两种排序),但与之相差甚远


同样在前一种情况下,将b循环拆分为缓存大小的块可以提高性能。i、 e.对照B[0…1023]检查A[0](如果您的缓存可以容纳1024项),然后检查A[1]。。。A[final],然后将A[0]与B[1024…2047]等进行比较。

由于整个数据集都可以(轻松地)装入RAM,因此不需要对其进行任何巧妙的排序,也不需要使用磁盘空间(首先加载数据之后)

我假设每个元素在每个列表中最多只能存在一次

哑(蛮力)法,O(n^2):

预排序方法:(2*n*log(n)+n),so(n*log(n))

我建议采用前者,但采用并行处理。很容易将外部循环分解成块,在处理器/工作站之间进行分割。后者也可以进行某种程度的并行化(同时执行两种排序),但与之相差甚远


同样在前一种情况下,将b循环拆分为缓存大小的块可以提高性能。i、 e.对照B[0…1023]检查A[0](如果您的缓存可以容纳1024项),然后检查A[1]。。。A[final],然后将A[0]与B[1024…2047]进行对比,以此类推。

假设,第一个arr是arr1,第二个是arr2

sort arr1//max O(n*log_n)
for(int i = 0; i < arr2.length; i++){ //n
    binarySearch(arr1, arr2[i]) //log_n
}
sort arr1//max O(n*log\n)
对于(int i=0;i

总的O(n logn)

假设,第一个arr是arr1,第二个是arr2

sort arr1//max O(n*log_n)
for(int i = 0; i < arr2.length; i++){ //n
    binarySearch(arr1, arr2[i]) //log_n
}
sort arr1//max O(n*log\n)
对于(int i=0;i

总的来说,O(nlogn)

就执行时间而言(但不幸的是,编程时间并非如此),最便宜的方法可能是将A中的元素放入A中,然后在哈希表中查找B中的每个元素。如果你能想出一个合理的散列函数(详见下文),那么你可以使用简单的线性散列,负载系数大约为60%,这意味着你的表将占用108*(1/.6)*8字节,或者大约1.3 GB。(我不知道有哪种语言在标准库中提供开放寻址哈希表;C++的无序_集是用桶链实现的,如果单个元素不是单独的存储分配,这只会稍微增加开销。一个好的分配器可能会使这一点成为可能。)

幸运的是,开放寻址线性探测哈希表非常容易编写,特别是在不需要处理删除元素的情况下。您只有两个问题:

  • 您需要保留一些值,这意味着“未占用”

  • 你需要一个好的散列函数。或者至少是合理的

  • 如果您的数据确实随机分布在64位空间中,那么散列很简单;您只需要将数据减少到所需的大小。一个简单的方法是使用模运算符,即使数据不是完全随机分布的,只要您将表大小设置为素数(166666783对于60%的负载因子和1亿个元素来说是合适的大小),它也应该可以很好地工作

    找到一个表示“未被占用”的值可能更为棘手。您可能已经知道一个值是不可能的(可能是值
    0
    )。如果不是,您可以选择一个随机的64位数字;它不存在于数据集中的可能性很高,但如果存在,您有一个简单的备份:不要将它放入哈希表中,并对照它检查
    B
    的每个值

    伪C++代码,基于上述描述,包括提到的“无值”黑客:

    class HundredMillionSet {
      std::vector<uint64_t> h_;
      const size_t size_
      const uint64_t no_value_;
      bool has_no_value_;
      HundredMillionSet(size_t size, uint64_t no_value)
          : h_(size, no_value), size_(size), no_value_(no_value), has_no_value_(false) {}
    
      void insert(uint64_t v) {
        if (v == no_value_) { has_no_value_ = true; }
        else {
          size_t i = v % size_;
          while (h_[i] != no_value_) {
            if (++i == size_) i = 0;
          }
          h_[i] = v;
        }
      }
    
      bool check(uint64_t v) {
        if (v == no_value_) return has_no_value_;
        size_t i = v % size_;
        while (h_[i] != v && h_[i] != no_value_) {
          if (++i == size_) i = 0;
        }
        return h_[i] == v;
      }
    };
    
    100毫米级{
    std::向量h;
    常量大小\u t大小_
    常数64无值;
    布尔h
    
    class HundredMillionSet {
      std::vector<uint64_t> h_;
      const size_t size_
      const uint64_t no_value_;
      bool has_no_value_;
      HundredMillionSet(size_t size, uint64_t no_value)
          : h_(size, no_value), size_(size), no_value_(no_value), has_no_value_(false) {}
    
      void insert(uint64_t v) {
        if (v == no_value_) { has_no_value_ = true; }
        else {
          size_t i = v % size_;
          while (h_[i] != no_value_) {
            if (++i == size_) i = 0;
          }
          h_[i] = v;
        }
      }
    
      bool check(uint64_t v) {
        if (v == no_value_) return has_no_value_;
        size_t i = v % size_;
        while (h_[i] != v && h_[i] != no_value_) {
          if (++i == size_) i = 0;
        }
        return h_[i] == v;
      }
    };