C++ 玩无序的多重映射

C++ 玩无序的多重映射,c++,c++11,hashmap,unordered-map,C++,C++11,Hashmap,Unordered Map,所以,伙计们,我玩std::无序多重映射只是为了好玩。我希望(在本例中)使用自定义哈希和等号来存储无符号shorts 有趣的是什么?如果两项都是偶数或奇数,则两项相等 因此,据我所知,我不能使用std::unordered_map,即使实际值不同:自定义谓词则相反。(显然,如果我错了,请纠正我!) 概括一下:我存储了不同的整数,因此也存储了不同的散列,但它们在谓词下的值可能是相同的 我是不是遗漏了什么?(答案显然是肯定的)您所做的是未定义的行为:相等的元素应该具有相等的哈希值。根据标准(重点矿山

所以,伙计们,我玩std::无序多重映射只是为了好玩。我希望(在本例中)使用自定义哈希和等号来存储
无符号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