C++ 玩无序的多重映射
所以,伙计们,我玩std::无序多重映射只是为了好玩。我希望(在本例中)使用自定义哈希和等号来存储C++ 玩无序的多重映射,c++,c++11,hashmap,unordered-map,C++,C++11,Hashmap,Unordered Map,所以,伙计们,我玩std::无序多重映射只是为了好玩。我希望(在本例中)使用自定义哈希和等号来存储无符号shorts 有趣的是什么?如果两项都是偶数或奇数,则两项相等 因此,据我所知,我不能使用std::unordered_map,即使实际值不同:自定义谓词则相反。(显然,如果我错了,请纠正我!) 概括一下:我存储了不同的整数,因此也存储了不同的散列,但它们在谓词下的值可能是相同的 我是不是遗漏了什么?(答案显然是肯定的)您所做的是未定义的行为:相等的元素应该具有相等的哈希值。根据标准(重点矿山
无符号short
s
有趣的是什么?如果两项都是偶数或奇数,则两项相等
因此,据我所知,我不能使用std::unordered_map
,即使实际值不同:自定义谓词则相反。(显然,如果我错了,请纠正我!)
概括一下:我存储了不同的整数,因此也存储了不同的散列,但它们在谓词下的值可能是相同的
我是不是遗漏了什么?(答案显然是肯定的)您所做的是未定义的行为:相等的元素应该具有相等的哈希值。根据标准(重点矿山) 23.2.5无序关联容器[unord.req] 5如果 当传递这些值时,容器的键相等谓词返回true 价值观如果k1和k2相等,则容器的哈希函数 应为两个返回相同的值
因为定义了模2的等价性,所以还需要对传递的整数的模2使用哈希函数。这还意味着,当您有2个以上的元素时,您就需要
std::unordered_multimap
。无序容器中的相等值用于标识存储的元素,因此您基本上将可能要存储的值减少到两个(奇数或偶数),并且必须相应地调整hashfunction(我建议使用x&1)Mmh。。。我真的很想有效地存储它们,但不是只存储在两个桶上,这将破坏使用无序的_多重映射的全部目的。有什么建议吗?为什么不使用typedef std::unordered_multiset[2]mymap
即,根据模2值是0还是1,将tt
对象散列为两个不同的集合。当然,现在需要将tt_equal
定义为u.i==v.i
(即没有%2
)。因为目标是在运行时生成谓词(当然,给定编译时模板)。所以,我想找到所有共享特定位的值,例如,或者是5的倍数。对于哈希表,我有几乎恒定的查找时间,当然最多N,但不保持任何顺序(我不关心值的顺序)。@senseiwa但无序容器有编译时谓词,因此如果您想要多个不相关的运行时谓词搜索,您可能最好使用普通的std::vector
和std:find_if
(对于N
元素,它具有O(N)
复杂性)。这只是灵活性的代价:容器只针对编译时指定的搜索进行优化。如果您想要固定数量的编译时搜索,请尝试允许多个哈希索引(为每个索引提供一个谓词)。是的,我知道我需要编译时谓词。但是如果我想要一个谓词来测试两个数是否相等,模为N
,其中N
是一个运行时变量,该怎么办?我知道我在做一些不寻常的事情,但我觉得很有趣。
#include <iostream>
#include <unordered_map>
class tt
{
public:
tt(const unsigned short v = 0) : i(v) { };
unsigned short i;
};
class tt_hash
{
public:
size_t operator()(const tt &v) const
{
auto f = std::hash<unsigned short>();
return f(v.i);
};
};
class tt_equal
{
public:
bool operator()(const tt &u, const tt &v) const
{
return (u.i % 2) == (v.i % 2);
};
};
typedef std::unordered_multimap<tt, bool, tt_hash, tt_equal> mymap;
// Print all values that match a criteria
void f(const mymap &m, unsigned short c)
{
auto range = m.equal_range(c);
auto target = range.first;
if (target == m.end())
{
std::cout << "not found : " << (int) c << std::endl;
}
else
{
for (auto i = target; i != range.second; i++)
std::cout << "there is : " << (int) i->first.i << " : " << i->second << std::endl;
}
}
int main(int argc, const char * argv[])
{
mymap m;
m.emplace(std::make_pair(tt(3), false));
m.emplace(std::make_pair(tt(10), true));
m.emplace(std::make_pair(tt(4), true));
m.emplace(std::make_pair(tt(23), false));
std::cout << "size " << m.size() << std::endl;
std::cout << "buck " << m.bucket_count() << std::endl;
int c = 0;
for (auto i = m.begin(); i != m.end(); i++)
std::cout << "# " << c++ << " : " << (int) i->first.i << " : " << i->second << std::endl;
f(m, 3);
return 0;
}
size 4
buck 5
# 0 : 4 : 1
# 1 : 10 : 1
# 2 : 3 : 0
# 3 : 23 : 0
there is : 10 : 1