以三个无符号字符为关键字的无序映射

Unordered Map with three unsigned chars as key

本文关键字:关键字 无序 映射 字符 无符号 三个      更新时间:2023-10-16

我必须制作一个由以下键和值组成的无序映射:

  • 键:无符号字符、无符号字符和无符号字符

  • value:structure(int,int)

以下是我定义的代码

namespace G {
typedef std::tuple< unsigned char, unsigned char , unsigned char> key_t;

struct IndexGuide
{
int index;
int SerialNo;
};
typedef std::unordered_map<const key_t,IndexGuide> GuideDouble;
}
using namespace G;

这段代码中有什么错误吗?因为当我在linux终端上链接这些文件时。它给了我错误。错误的某些部分如下

在函数`std::__detail::_Hash_code_base const,std::pair const,G::IndexGuide>中,std::_Select 1st const,G::IndexGuide>>,std::equal_toconst>,std::hash const>,td::__detail::_Mod_range_hashing,std::__detail::_Default_ranged_hash,false>::_M_bucket_index(std::__detail::_Hash_node const,G::IndexGuide>,false>const*,unsigned int)const':

因此,您的基本问题是没有std::tuple的哈希器——默认情况下,标准库当前没有哈希器。我认为这是一个疏忽。

您不能为std::tuple添加默认哈希器——无论是为所有tuple还是为您的特定列表——因为标准规定您不允许:

17.6.4.2.1命名空间std〔Namespace.std〕/1如果C++程序将声明或定义添加到命名空间std或命名空间std中的命名空间,除非另有说明指定。程序可以为任何仅当声明取决于用户定义的类型,并且专业化满足原始模板的标准库要求,而不是明确禁止。

因此,您要么为tuple类型编写一个自定义哈希器,并将其传递给unordered_map,要么为密钥使用一个不仅仅是std::tuple的类型,或者编写一个自定义哈希器,支持每个tuple(包括递归tuples),同时也支持非tuples的hash<T>查找。第四种选择是编写自己的基于ADL的哈希系统,并对其进行设置,以便具有有效std::hash专业化的类型使用该哈希系统,以及各种其他回退。

我将说明上面的第三个选项。

首先,您希望能够以一种不会导致许多虚假冲突的方式组合两个哈希值。

inline std::size_t hash_result_combine(std::size_t lhs, std::size_t rhs)
{
return lhs ^( rhs + 0x9e3779b9 + (lhs<<6) + (lhs>>2));
}

这需要两个hash输出并将它们组合。然后我们可以将其链接任意次数。(常数借用自https://stackoverflow.com/a/7111460/1774667)

接下来,介绍一些索引样板。std::tuple的大多数通用工作都需要以下内容:

template<unsigned...>struct indexes{};
template<unsigned Max, unsigned... Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...> {};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};

最后,一个几乎适用于所有类型的hasher类:

struct my_hasher {
template<typename... Args>
std::size_t operator()(indexes<>, std::tuple<Args...> const& tup) const {
return 0;
}
template<unsigned I, unsigned... Is,typename... Args>
std::size_t operator()(indexes<I, Is...>,std::tuple<Args...> const& tup) const {
return hash_result_combine( (*this)(std::get<I>(tup)), (*this)(indexes<Is...>, tup) );
}
template<typename... Args>
std::size_t operator()(std::tuple<Args...> const& tup) const {
return (*this)(make_indexes<sizeof...(Args)>(), tup);
}
template<typename T>
std::size_t operator()(T const& t) const { return std::hash<T>()(t); }
};

对于tuples、包含元组的tuples,甚至对于标量,可以将my_hasher传递给unordered_set来代替hash<T>,这是非常慷慨的。

typedef std::unordered_map<const key_t,IndexGuide, my_hasher> GuideDouble;

现在我们对CCD_ 19进行适当的散列。

您必须提供一个散列函数,该函数告诉std::unordered_map如何从key_t生成散列值。您可以通过hash模板函数的专业化来实现

提供密钥:

struct Key{
unsigned char  first;
unsigned char second;
unsigned char  third;
bool operator==(const Key &other) const {
return (first == other.first
&& second == other.second
&& third == other.third);
}
};

specialized散列模板:

namespace std {
template <>
struct hash< Key>
{
std::size_t operator()(const Key& k) const
{
using std::hash;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<char>()( k.first)
^ (hash<char>()( k.second) << 1)) >> 1)
^ (hash<int>()( k.third) << 1);
}
};
}
std::unordered_map< Key, IndexGuide> myMap;

正如我在评论中所说,你可以看看这个SO线程。

unordered_set是使用哈希表实现的
为了将unordered_set用于您定义的类型,您需要专门化该类型的hash<>模板,如下所示:

namespace std {
template <> struct hash<key_t>
{
size_t operator()(const key_t & t) const
{
// the logic for hashing
}
};
}

std::tuple没有默认的hasher。

您可以使用以下代码片段Unrderede_map/undered_set 中元组的通用哈希