C++ 无序多集的hash/crc算法
假设我想创建一个无符号int的无序多集的无序集。为此,我需要创建一个散列函数来计算无序多集的散列。事实上,这对CRC也有好处 一个明显的解决方案是将项目放入向量中,对它们进行排序并返回结果的散列。这似乎管用,但很贵 另一种方法是对值进行异或运算,但很明显,如果有一个项两次或没有,结果将是相同的——这是不好的C++ 无序多集的hash/crc算法,c++,algorithm,hash,crc,C++,Algorithm,Hash,Crc,假设我想创建一个无符号int的无序多集的无序集。为此,我需要创建一个散列函数来计算无序多集的散列。事实上,这对CRC也有好处 一个明显的解决方案是将项目放入向量中,对它们进行排序并返回结果的散列。这似乎管用,但很贵 另一种方法是对值进行异或运算,但很明显,如果有一个项两次或没有,结果将是相同的——这是不好的 我有一个应用程序,它可以为数千个集合和相对较大的集合实现这一千个集合。将内部多集合实现为一个值->计数哈希映射 这将允许您通过以下方式避免偶数个元素通过xor抵消的问题:您不必对每个元素进行
我有一个应用程序,它可以为数千个集合和相对较大的集合实现这一千个集合。将内部多集合实现为一个值->计数哈希映射
这将允许您通过以下方式避免偶数个元素通过xor抵消的问题:您不必对每个元素进行xor运算,而是根据计数和值构造一个新的数字(例如,将它们相乘),然后可以使用xor构建完整的哈希 由于它是一个多集,您希望相同的多集的哈希值相同,这些多集的表示可能以不同的顺序显示、添加或删除相同的元素。然后,您希望哈希值是可交换的、易于更新的,并且随着元素的每次更改而更改。您还希望两个更改不会轻易取消它们对散列的影响 除最后一个条件外,满足所有条件的一个操作是加法。只需对元素求和即可。要保持和有界,请对哈希值的大小进行和模运算。(例如,64位散列的模264。)要确保插入或删除零值会更改散列,请先为每个值添加一个
这个总和的一个缺点是两个变化很容易被抵消。例如,将1 3替换为2 2。为了解决这个问题,您可以使用相同的方法,对条目的多项式求和,仍然保持交换性。例如,您可以对x2+x+1求和,而不是对x+1求和。现在,用相同的和来设计一组变化就更难了。这里有一个合理的哈希函数,用于
std::unordered\u multiset
如果将计算取为一个大素数会更好,但这个想法是正确的
#include <iostream>
#include <unordered_set>
namespace std {
template<>
struct hash<unordered_multiset<int>> {
typedef unordered_multiset<int> argument_type;
typedef std::size_t result_type;
const result_type BASE = static_cast<result_type>(0xA67);
result_type log_pow(result_type ex) const {
result_type res = 1;
result_type base = BASE;
while (ex > 0) {
if (ex % 2) {
res = res * base;
}
base *= base;
ex /= 2;
}
return res;
}
result_type operator()(argument_type const & val) const {
result_type h = 0;
for (const int& el : val) {
h += log_pow(el);
}
return h;
}
};
};
int main() {
std::unordered_set<std::unordered_multiset<int>> mySet;
std::unordered_multiset<int> set1{1,2,3,4};
std::unordered_multiset<int> set2{1,1,2,2,3,3,4,4};
std::cout << "Hash 1: " << std::hash<std::unordered_multiset<int>>()(set1)
<< std::endl;
std::cout << "Hash 2: " << std::hash<std::unordered_multiset<int>>()(set2)
<< std::endl;
return 0;
}
当它是素数p时,碰撞的次数与1/p成正比。我不确定二次幂的分析是什么。插入/删除整数x时,通过添加/减去基数^x,可以有效地更新哈希值。是否可以修改多集,以便它们在插入/删除时重新计算哈希值?然后,如果需要多次查找,则不必不断重新计算哈希值。从技术上讲,是的,但这有什么帮助?因为缓存的值可以简单地读取,所以不需要计算数千次。我有数千个集合,我不会一次又一次地对同一集合执行此操作。但这是否正确。例如,对于16位,如果我从0xFFFF开始,如果添加另一个0xFFFF,0xFFFF+0xFFFF=0x7FFF,那么如果我删除它0x7FFF-0xFFFF=0x7FFF-初始值和结束值不相同。模2^16:0xFFFF+0xFFFF=0xFFFE,0x7FFF-0xFFFF=0x8000。当然,0xFFFE-0xFFFF=0xFFFF。
Hash 1: 2290886192
Hash 2: 286805088