我有一个数据池(X 1 .. X N ),我想要找到相同值的组。比较非常昂贵,我无法将所有数据保存在内存中。
我需要的结果是,例如:
X 1 等于X 3 和X 6
X 2 是唯一的 X 4 等于X 5
(行的顺序或行内的顺序无关紧要)。
如何通过成对比较实现这一点?
这是我到目前为止所拥有的:
比较所有对(X i ,X k )与i< k,和利用传递性:如果我已经找到X 1 == X 3 且X 1 == X 6 ,我不需要比较X 3 和X 6 。
所以我可以使用以下数据结构:
map: index --> group
multimap: group --> indices
其中任意分配组(例如输出中的“行号”)。
对于一对(X i ,X k ),其中i < k:
如果i和k已经分配了一个组,请跳过
如果他们比较相等:
如果不相等:
如果我对项目的顺序非常谨慎,那么应该工作,但我想知道这是否是解决这个问题的最佳/最不令人惊讶的方法,因为这个问题似乎有些常见。
背景/更多信息:目的是对项目的存储进行重复数据删除。他们已经有一个哈希,如果发生碰撞,我们希望保证完整的比较。所讨论数据的大小具有非常尖锐的长尾分布。
迭代算法(找到任意两个重复项,共享它们,重复直到没有重复项)可能会更容易,但我们需要非修改诊断。 代码库是C ++,适用于STL / boost容器或算法的东西会很好。
[edit] 关于哈希:出于这个问题的目的,请假设一个无法替换的弱哈希函数。
这需要对现有数据进行一次性重复数据删除,并且需要处理哈希冲突。最初的选择是“快速哈希,并在碰撞时进行比较”,所选择的哈希结果有点弱,但改变它会破坏向后兼容性。即便如此,我还是会用一个简单的声明睡得更好:如果发生碰撞,你就不会得到错误的数据。而不是关于wolf attacks的博客。
答案 0 :(得分:1)
制作每个项目的哈希值。列出pair<hash,item_index>
。您可以通过哈希对此列表进行排序或将其放入std::multimap
来查找组。
输出组列表时,需要比较哈希冲突的项目。 因此,对于每个项目,您将进行一次哈希计算和一次比较。并排序哈希列表。
答案 1 :(得分:1)
所以......你已经有了哈希?怎么样:
比较colisions的提示:为什么不用其他算法重新进行比较呢?冲洗,重复。
(我假设你在这里存储文件/ blob /图像并且有哈希值,你可以将哈希值插入内存中,哈希就像sha1 / md5等,所以碰撞是不太可能的)
(另外,我假设两种不同的哈希算法不会在不同的数据上发生冲突,但这可能是安全的假设......)
答案 2 :(得分:1)
这是另一种可能更简单的数据结构,用于利用传递性。制作一个需要进行比较的队列。例如,在4项的情况下,它将是[(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)] 。还有一个阵列用于比较你已经完成的。在每次比较之前,检查之前是否已完成比较,并且每次找到匹配项时,请检查队列并将匹配项目索引替换为其较低的索引等效项。
例如,假设我们弹出(1,2),比较,它们不相等,将(1,2)推送到already_visited
的数组并继续。接下来,弹出(1,3)并发现它们是相等的。此时,通过队列并用1替换所有3。队列将是[(1,4),(2,1),(2,4),(1,4)],依此类推。当我们到达(2,1)时,它已被访问过,所以我们跳过它,和(1,4)一样。
但我同意以前的答案。由于比较计算成本很高,您可能希望首先计算快速,可靠的哈希表,然后才将此方法应用于冲突。
答案 3 :(得分:0)
我同意使用第二个(希望改进的)哈希函数的想法,这样你就可以解决一些弱哈希冲突,而无需进行昂贵的成对比较。既然你说你有内存限制问题,希望你可以将整个哈希表(带有辅助密钥)放在内存中,对于表中的每个条目,你存储磁盘上与该密钥对应的记录的记录索引列表对。然后问题是,对于每个密钥对,是否可以将所有记录加载到具有该密钥对的内存中。如果是这样,那么你可以迭代密钥对;对于每个密钥对,释放内存中任何前一个密钥对的记录,并将记录加载到当前密钥对的内存中,然后像您已经概述的那样对这些记录进行比较。如果你有一个密钥对,你无法将所有记录放入内存,那么你将不得不加载部分子集,但你绝对应该能够在内存中维护所有组(每个组有一个唯一的记录代表)你找到了密钥对,因为如果你有一个好的二级哈希,唯一记录的数量会很小。