std :: unordered_map的哈希值

时间:2015-06-28 10:04:51

标签: c++ c++11 hash unordered-map

根据标准,<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:scrollbars="vertical" android:layout_width="320dp" android:layout_height="match_parent" android:layout_gravity="left" android:background="@color/orange"> </android.support.v7.widget.RecyclerView> 类中不支持容器(更不用说无序容器)了。所以我想知道如何实现这一点。我所拥有的是:

std::hash

我考虑过迭代条目,计算键和值的各个哈希值(通过std::unordered_map<std::wstring, std::wstring> _properties; std::wstring _class; )并以某种方式连接结果。

如果没有定义地图中的订单,那么这样做有什么好办法呢?

注意:我不想使用boost。

建议使用简单的XOR,因此它会是这样的:

std::hash<std::wstring>

我真的不确定这个简单的XOR是否足够。

1 个答案:

答案 0 :(得分:8)

响应

如果足够了,你的意思是你的函数是否是单射的,答案是否定的。理由是你的函数可以输出的所有散列值的集合的基数为2 ^ 64,而输入的空间是<强>多大。但是,这并不重要,因为根据输入的性质,你不能有一个单射散列函数。一个好的哈希函数具有以下特性:

  • 它不容易翻转。给定输出k,在宇宙的生命周期内找到m使得h(m)= k在计算上是不可行的。
  • 范围均匀分布在输出空间上。
  • 很难找到两个输入m和m',使得h(m)= h(m')

当然,这些的范围实际上取决于您是否想要一些加密安全的东西,或者您想要获取一些任意数据块并且只是发送一些任意的64位整数。如果你想要一些加密安全的东西,自己编写它并不是一个好主意。在这种情况下,您还需要保证函数对输入中的微小变化敏感。 std::hash函数对象不需要加密安全。它存在用于哈希表同构的用例。 CPP Rerefence说:

  

对于不相等的两个不同参数k1k2std::hash<Key>()(k1) == std::hash<Key>()(k2)应该非常小,接近1.0/std::numeric_limits<size_t>::max()的概率。

我将在下面说明您当前的解决方案并不能真正保证这一点。

的碰撞

我会就您的解决方案的变体(我不知道您的_class成员是什么)向我提供一些观察。

std::size_t hash_code(const std::unordered_map<std::string, std::string>& m) {
    std::hash<std::string> h;
    std::size_t result = 0;
    for (auto&& p : m) {
        result ^= h(p.first) ^ h(p.second);
    }
    return result;
}

很容易产生碰撞。请考虑以下地图:

std::unordered_map<std::string, std::string> container0;
std::unordered_map<std::string, std::string> container1;
container0["123"] = "456";
container1["456"] = "123";
std::cout << hash_code(container0) << '\n';
std::cout << hash_code(container1) << '\n';

在我的机器上,用g ++ 4.9.1编译,输出:

1225586629984767119
1225586629984767119

是否重要的​​问题出现了。与此相关的是,您有多少时间可以获得键和值相反的地图。这些碰撞将发生在任意两组映射之间,其中键和值集是相同的。

迭代顺序

具有完全相同键值对的两个unordered_map个实例不一定具有相同的迭代次序。 CPP Rerefence说:

  

对于两个相等的参数k1k2std::hash<Key>()(k1) == std::hash<Key>()(k2)

这是哈希函数的一个简单要求。您的解决方案避免了这种情况,因为迭代的顺序无关紧要,因为XOR是可交换的。

可能的解决方案

如果您不需要加密安全的东西,您可以稍微修改您的解决方案以消除对称性。对于散列表等,这种方法在实践中是可行的。此解决方案也独立于unordered_map中的顺序未定义的事实。它使用您的解决方案使用的相同属性(XOR的交换)。

std::size_t hash_code(const std::unordered_map<std::string, std::string>& m) {
    const std::size_t prime = 19937;
    std::hash<std::string> h;
    std::size_t result = 0;
    for (auto&& p : m) {
        result ^= prime*h(p.first) + h(p.second);
    }
    return result;
}

在这种情况下,哈希函数中所需要的只是将键值对映射到任意良好哈希值的方法,以及使用可交换操作组合键值对的哈希的方法。这样,顺序无关紧要。在我写的示例hash_code中,键值对散列值只是键的散列和值的散列的线性组合。你可以构造一些更复杂的东西,但没有必要。