【问题标题】:unordered_map hash function c++unordered_map 哈希函数 C++
【发布时间】:2011-11-05 12:48:57
【问题描述】:

我需要定义一个类似unordered_map<pair<int, int>, *Foo> 的unordered_map,定义hashequal 函数并将其传递给此映射的语法是什么?

我尝试将这个对象传递给它:

class pairHash{
public:
    long operator()(const pair<int, int> &k) const{
        return k.first * 100 + k.second;
    }
};

没有运气:

unordered_map<pair<int, int>, int> map = unordered_map<pair<int, int>, int>(1,
*(new pairHash()));

我不知道size_type_Buskets 是什么意思,所以我给了它1。 正确的方法是什么? 谢谢。

【问题讨论】:

  • *(new pairHash()) 谁来删除这个?为什么要在这里做动态分配?只需使用pairHash()

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


【解决方案1】:

这是 C++11 中不幸的遗漏; Boost 的答案是hash_combine。随意从他们那里粘贴它!以下是我如何散列对:

template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

namespace std
{
  template<typename S, typename T> struct hash<pair<S, T>>
  {
    inline size_t operator()(const pair<S, T> & v) const
    {
      size_t seed = 0;
      ::hash_combine(seed, v.first);
      ::hash_combine(seed, v.second);
      return seed;
    }
  };
}

您可以使用hash_combine 作为许多其他事物的基础,例如元组和范围,因此您可以对整个(有序)容器进行哈希处理,例如,只要每个成员都可以单独进行哈希处理。

现在您可以声明一个新地图:

std::unordered_map<std::pair<int, int>, my_mapped_type> mymap;

如果你想使用你的自制散列器(它没有很好的统计属性),你必须明确指定模板参数:

std::unordered_map<std::pair<int,int>, int, pairHash> yourmap;

请注意,不需要指定哈希对象的副本,因为默认情况下会为您默认构造一个。

【讨论】:

  • @Vlad: 嗯......好吧,使用pair hash专门化,你可以写std::unordered_map&lt;std::pair&lt;int, int&gt;, int&gt; map;,不用再担心......如果你真的想要一个命名的哈希,你必须指定所有四个模板参数,&lt;Key, Value, EqualPred, Hasher&gt;.
  • 哇,敌意很容易 :-) 检查我之前的评论:如果你想指定你自己的哈希类,你必须明确命名所有四个模板参数,你没有这样做。我添加了一行关于如何做到这一点。
  • @Kerrek SB 你弄错了 4 个模板参数的顺序,等于谓词跟在哈希后面。另外,我比我发布的更喜欢这种方法,但也许 Vlad 必须使用这个自定义哈希函数。
  • @Praetorian:哦,谢谢你,太傻了——这样就容易多了,因为你根本不需要列出第四个参数。
  • @Kerrek SB 不,您似乎没有。我不知道有一个为std::pair 定义的operator==
【解决方案2】:

哈希函数的返回类型应该是size_t,而不是long(虽然这不是错误的原因)。您为提供自定义哈希函数显示的语法不正确。

您还需要提供相等的谓词以使上述工作正常。

#include <unordered_map>
#include <utility>

using namespace std;

class pairHash{
public:
    size_t operator()(const pair<int, int> &k) const{
        return k.first * 100 + k.second;
    }
};

struct pairEquals : binary_function<const pair<int,int>&, const pair<int,int>&, bool> {
  result_type operator()( first_argument_type lhs, second_argument_type rhs ) const
  {
    return (lhs.first == rhs.first) && (lhs.second == rhs.second);
  }
};     

int main()
{
  unordered_map<pair<int, int>, int, pairHash, pairEquals> myMap;

  myMap[make_pair(10,20)] = 100;
  myMap.insert( make_pair(make_pair(100,200), 1000) );
}

编辑:
您不需要定义相等谓词,因为operator== 是为std::pair 定义的,它完全符合我在pairEquals 中所做的事情。如果您希望以不同方式进行比较,则只需要 pairEquals 定义。

【讨论】:

【解决方案3】:

如果您对使用 Boost 感到满意,一个更简洁的解决方案是依赖 Boost 对对的散列函数的实现(实际上,这正是 kerrek-sb 在他的回答中所解释的)。因此,您所要做的就是:

#include <unordered_map>
#include <boost/functional/hash.hpp>

using namespace std;
using namespace boost;

unordered_map<pair<int, int>, int, hash<pair<int, int>>> table;

【讨论】:

  • 一个很好的解决方案,但我不会使用命名空间。我会把它写出来。什么来自哪个命名空间非常重要。
  • 我也非常感谢这个答案,我不确定最佳答案是否应该被视为一个好习惯。定义这样的自制辅助函数只会污染代码恕我直言。
猜你喜欢
  • 1970-01-01
  • 2013-03-13
  • 2016-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-23
  • 2020-11-12
相关资源
最近更新 更多