我有大约20,000,000 pair<int, int>
我需要与int
相关联。我用unordered_map<pair<int, int>, int>
这样做了。分析我的算法表明检查条目是否存在
bool exists = myMap[make_pair(a, b)] != NULL
是性能瓶颈。我认为从unordered_map
检索此信息会非常快,因为它是 O(1)。但如果常数很大,恒定时间可能会很慢......
我的哈希函数是
template <>
struct tr1::hash<pair<int, int> > {
public:
size_t operator()(pair<int, int> x) const throw() {
size_t h = x.first * 1 + x.second * 100000;
return h;
}
};
你知道我的问题有更好的数据结构吗?
显然,我不能将信息存储在矩阵中,因此内存量不适合现有的任何计算机。我所知道的分布是myMap[make_pair(a, a)]
对于任何a
都不存在。并且所有int
都在0到大约20,000,000的连续范围内。
将其视为稀疏的20,000,000x20,000,000-Matrix,大约有20,000,000个条目,但从不在主对角线上。
vector<pair<int, int>>*
(带有 N 条目的数组)预计会更快吗?查找a
将是微不足道的(只是数组的索引),然后我将迭代向量,将对的first
值与b
进行比较。
我上传了raw data,因此您可以看到结构。
答案 0 :(得分:5)
您是否尝试过使用myMap.find(make_pair(a,b)) != myMap.end()
?如果元素不存在,operator[]
会创建该元素。我希望find
更快。
答案 1 :(得分:3)
首先,myMap[make_pair(a, b)] != NULL
没有按照您的想法行事。如果它不存在,则插入该对,并将映射的值与0(NULL
扩展为)进行比较。它根本不检查是否存在。 (请注意,在现代C ++中,绝不能使用NULL
。数字使用0,指针使用nullptr
。
至于主题,你的哈希函数似乎不太好。不要忘记int
s上的算术是在int
s中完成的。由于大多数编译器int
是32位,因此其最大值略高于2,000,000,000。因此,20,000,000 * 10,000比这更大,导致溢出(和未定义的行为)。
鉴于您的数据数量,我假设您使用的是64位平台,这意味着size_t
长度为64位。因此,使用这样的哈希函数可能会得到更好的结果:
size_t operator()(pair<int, int> x) const throw() {
size_t f = x.first, s = x.second;
return f << (CHAR_BIT * sizeof(size_t) / 2) | s;
}
这应该会产生与你现在拥有的冲突明显更少的冲突(并且已经定义了行为)。
如果这没有帮助,您还可以尝试两步法:
std::unordered_map<int, std::unordered_map<int, int>>
首先按x.first
查找,然后按x.second
查找。我不知道这是否会有所帮助;衡量和看。
答案 2 :(得分:2)
主要的是避免在每次搜索时添加默认构造的元素:
bool exists = myMap[make_pair(a, b)] != NULL; // OUCH
bool exists = myMap.find(make_pair(a, b)) != myMap.end(); // BETTER
iterator i = myMap.find(make_pair(a, b);
if (i != myMap.end()) ... else ...; // MAY BE BEST - SEE BELOW
伟大的哈希挑战......呜啊!这可能值得一试,但很大程度上取决于对中的数字如何分配以及您的实现std::hash
(通常是传递!):
size_t operator()(pair<int, int> x) const throw() {
size_t hf = std::hash(x.first);
return (hf << 2) ^ (hf >> 2) ^ std::hash(x.second);
}
如果用int64_t
替换对,可能也会更快找到它,因此关键比较肯定是简单的整数比较而不是级联。
另外,在测试存在后你在做什么?如果您需要访问/更改与相同键关联的值,则应保存迭代器find
返回并避免其他搜索。
答案 3 :(得分:1)
正如建议的那样,我选择了带有 N 条目的vector<pair<int, int>>*
。它比unordered_map
快了大约40%。
答案 4 :(得分:0)
我建议您使用更好的哈希函数进行测试。如果您在此处搜索SO,可以找到示例,但这是一种可能的实现方式。
struct pair_hash {
template <typename T1, typename T2>
size_t operator()(const std::pair<T1, T2> &pr) const {
using std::hash;
return hash<T1>()(pr.first) ^ hash<T2>()(pr.second);
}
};