Algorithm 找到两个集合之间的重复项的有效方法是什么?
我设置了A和B 集合A有1亿个数字(每个数字为64位) 集合B有1亿个数字(每个数字为64位) 两套尺寸相同 数据都是随机的,没有排序 您建议使用什么算法来查找两个集合之间的重复数 (我可以利用大约4G内存和100~200GB磁盘空间)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…树)。只需将数字从一个集合添加到一棵树,从另一个集合添加到另一棵树,然后进
提前感谢您。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++的无序_集是用桶链实现的,如果单个元素不是单独的存储分配,这只会稍微增加开销。一个好的分配器可能会使这一点成为可能。) 幸运的是,开放寻址线性探测哈希表非常容易编写,特别是在不需要处理删除元素的情况下。您只有两个问题:
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;
}
};