c++中的哈希map,即unorder_set与unorder_map如何使用结构体作为key
示例代码如下:
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
using namespace std;
struct MyStruct {
int width;
int height;
string name;
public:
MyStruct(int a, int b,string str)
{
width = a;
height = b;
name = str;
}
//重载 == 与下面仿函数MyStruct_equal的方法效果一致,如果选择重载 == 则在构造的时候只需要传入自定义的hash函数
// bool operator==( const MyStruct& rc2) const noexcept
// {
// return width == rc2.width && height == rc2.height && name == rc2.name;
// }
};
//哈希函数
struct MyStruct_hash
{
size_t operator()(const MyStruct& r1) const
{
return hash<string>()(r1.name) ^ hash<int>()(r1.width) ^ hash<int>()(r1.height);
}
};
//equal相当于重载operator==
struct MyStruct_equal
{
bool operator()(const MyStruct& rc1, const MyStruct& rc2) const noexcept
{
return rc1.width == rc2.width && rc1.height == rc2.height && rc1.name == rc2.name;
}
};
void hashset_test()
{
unordered_set < MyStruct, MyStruct_hash, MyStruct_equal> myStructSet;
myStructSet.insert({ 0,0,"struct0" });
myStructSet.insert({ 1,1,"struct1" });
myStructSet.insert({ 2,2,"struct2" });
myStructSet.insert({ 3,3,"struct3" });
cout<<"Test using struct as the key of unordered_set"<<endl;
for (auto it = myStructSet.begin(); it != myStructSet.end(); ++it)
{
cout << "name=" << it->name << ",width=" << it->width << ",heigh=" << it->height << endl;
}
}
void hashmap_test()
{
unordered_map<MyStruct,int,MyStruct_hash,MyStruct_equal> myStructMap;
// unordered_map<MyStruct,int,MyStruct_hash> myStructMap; // 如果重载了 == 则省去MyStruct_equal参数
myStructMap[{ 0,0,"struct0" }] = 0;
myStructMap[{ 1,1,"struct1" }] = 1;
myStructMap[{ 2,2,"struct2" }] = 2;
myStructMap.insert(unordered_map<MyStruct,int,MyStruct_hash,MyStruct_equal>::value_type({ 3,3,"struct3" },3));
cout<<"Test using struct as the key of unordered_map"<<endl;
for( auto i : myStructMap )
{
cout << "name=" << i.first.name<< ",width=" << i.first.width << ",heigh=" << i.first.height << ",value=" <<i.second<< endl;
}
}
int main(int argc, char const *argv[])
{
hashset_test();
hashmap_test();
return 0;
}
运行结果:
当然,因为哈希map和哈希set是无序的,所以输出是无序的
依据:
unorder_set.h
中定义如下
/**
* @brief A standard container composed of unique keys (containing
* at most one of each key value) in which the elements' keys are
* the elements themselves.
*
* @ingroup unordered_associative_containers
*
* @tparam _Value Type of key objects.
* @tparam _Hash Hashing function object type, defaults to hash<_Value>.
* @tparam _Pred Predicate function object type, defaults to
* equal_to<_Value>.
*
* @tparam _Alloc Allocator type, defaults to allocator<_Key>.
*
* Meets the requirements of a <a href="tables.html#65">container</a>, and
* <a href="tables.html#xx">unordered associative container</a>
*
* Base is _Hashtable, dispatched at compile time via template
* alias __uset_hashtable.
*/
template<typename _Value,
typename _Hash = hash<_Value>,
typename _Pred = equal_to<_Value>,
typename _Alloc = allocator<_Value>>
class unordered_set
{
typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;
......
也就是说,如果使用自定义结构体,需要重载hash
函数和equal
函数
同理,查看unorder_map.h
中定义
/**
* @brief A standard container composed of unique keys (containing
* at most one of each key value) that associates values of another type
* with the keys.
*
* @ingroup unordered_associative_containers
*
* @tparam _Key Type of key objects.
* @tparam _Tp Type of mapped objects.
* @tparam _Hash Hashing function object type, defaults to hash<_Value>.
* @tparam _Pred Predicate function object type, defaults
* to equal_to<_Value>.
* @tparam _Alloc Allocator type, defaults to
* std::allocator<std::pair<const _Key, _Tp>>.
*
* Meets the requirements of a <a href="tables.html#65">container</a>, and
* <a href="tables.html#xx">unordered associative container</a>
*
* The resulting value type of the container is std::pair<const _Key, _Tp>.
*
* Base is _Hashtable, dispatched at compile time via template
* alias __umap_hashtable.
*/
template<typename _Key, typename _Tp,
typename _Hash = hash<_Key>,
typename _Pred = equal_to<_Key>,
typename _Alloc = allocator<std::pair<const _Key, _Tp>>>
class unordered_map
{
typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;
......
相比set,map只需要多加一个value类型即可。