C++ C++;使用自定义类类型作为键的无序映射
我正在尝试使用自定义类作为C++ C++;使用自定义类类型作为键的无序映射,c++,hash,g++,unordered-map,hashtree,C++,Hash,G++,Unordered Map,Hashtree,我正在尝试使用自定义类作为无序\u映射的键,如下所示: #include <iostream> #include <algorithm> #include <unordered_map> using namespace std; class node; class Solution; class Node { public: int a; int b; int c; Node(){} Node(vector<
无序\u映射的键,如下所示:
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
class node;
class Solution;
class Node {
public:
int a;
int b;
int c;
Node(){}
Node(vector<int> v) {
sort(v.begin(), v.end());
a = v[0];
b = v[1];
c = v[2];
}
bool operator==(Node i) {
if ( i.a==this->a && i.b==this->b &&i.c==this->c ) {
return true;
} else {
return false;
}
}
};
int main() {
unordered_map<Node, int> m;
vector<int> v;
v.push_back(3);
v.push_back(8);
v.push_back(9);
Node n(v);
m[n] = 0;
return 0;
}
#包括
#包括
#包括
使用名称空间std;
类节点;
类解决方案;
类节点{
公众:
INTA;
int b;
INTC;
节点(){}
节点(向量v){
排序(v.begin(),v.end());
a=v[0];
b=v[1];
c=v[2];
}
布尔运算符==(节点i){
如果(i.a==this->a&&i.b==this->b&&i.c==this->c){
返回true;
}否则{
返回false;
}
}
};
int main(){
无序地图m;
向量v;
v、 推回(3);
v、 推回(8);
v、 推回(9);
节点n(v);
m[n]=0;
返回0;
}
但是,g++给了我以下错误:
In file included from /usr/include/c++/4.6/string:50:0,
from /usr/include/c++/4.6/bits/locale_classes.h:42,
from /usr/include/c++/4.6/bits/ios_base.h:43,
from /usr/include/c++/4.6/ios:43,
from /usr/include/c++/4.6/ostream:40,
from /usr/include/c++/4.6/iostream:40,
from 3sum.cpp:4:
/usr/include/c++/4.6/bits/stl_function.h: In member function ‘bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Node]’:
/usr/include/c++/4.6/bits/hashtable_policy.h:768:48: instantiated from ‘bool std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, false>::_M_compare(const _Key&, std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, false>::_Hash_code_type, std::__detail::_Hash_node<_Value, false>*) const [with _Key = Node, _Value = std::pair<const Node, int>, _ExtractKey = std::_Select1st<std::pair<const Node, int> >, _Equal = std::equal_to<Node>, _H1 = std::hash<Node>, _H2 = std::__detail::_Mod_range_hashing, std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, false>::_Hash_code_type = long unsigned int]’
/usr/include/c++/4.6/bits/hashtable.h:897:2: instantiated from ‘std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node* std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_M_find_node(std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node*, const key_type&, typename std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Hash_code_type) const [with _Key = Node, _Value = std::pair<const Node, int>, _Allocator = std::allocator<std::pair<const Node, int> >, _ExtractKey = std::_Select1st<std::pair<const Node, int> >, _Equal = std::equal_to<Node>, _H1 = std::hash<Node>, _H2 = std::__detail::_Mod_range_hashing, _Hash = std::__detail::_Default_ranged_hash, _RehashPolicy = std::__detail::_Prime_rehash_policy, bool __cache_hash_code = false, bool __constant_iterators = false, bool __unique_keys = true, std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node = std::__detail::_Hash_node<std::pair<const Node, int>, false>, std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::key_type = Node, typename std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Hash_code_type = long unsigned int]’
/usr/include/c++/4.6/bits/hashtable_policy.h:546:53: instantiated from ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::operator[](const _Key&) [with _Key = Node, _Pair = std::pair<const Node, int>, _Hashtable = std::_Hashtable<Node, std::pair<const Node, int>, std::allocator<std::pair<const Node, int> >, std::_Select1st<std::pair<const Node, int> >, std::equal_to<Node>, std::hash<Node>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::mapped_type = int]’
3sum.cpp:149:5: instantiated from here
/usr/include/c++/4.6/bits/stl_function.h:209:23: error: passing ‘const Node’ as ‘this’ argument of ‘bool Node::operator==(Node)’ discards qualifiers [-fpermissive]
make: *** [threeSum] Error 1
在/usr/include/c++/4.6/string:50:0中包含的文件中,
从/usr/include/c++/4.6/bits/locale_classes.h:42,
从/usr/include/c++/4.6/bits/ios_base.h:43,
从/usr/include/c++/4.6/ios:43,
从/usr/include/c++/4.6/ostream:40,
从/usr/include/c++/4.6/iostream:40,
从3sum.cpp:4:
/usr/include/c++/4.6/bits/stl_function.h:在成员函数“bool std::equal_to::operator()(const_Tp&,const_Tp&)const[with _Tp=Node]”中:
/usr/include/c++/4.6/bits/hashtable_policy.h:768:48:从“bool std::_detail::_Hash_code_base:::_M_compare(const _Key&,std:_detail:_Hash_code_base:_Hash_code_type,std:_detail:_Hash_detail::_Hash_node*)const[与Key=Node、Value=std::pair、ExtractKey=std::Select1st、Equal=std::Equal_uto、H1=std::hash、H2=std::u详细信息::uuu散列code type=long unsigned int]”
/usr/include/c++/4.6/bits/hashtable.h:897:2:实例化自'std::_hashtable::_Node*std::_hashtable::_M_find_Node(std:_hashtable::_Node*,const key_type&,typename std:_hashtable::_Hash_code_type)const[with_Key=Node,_Value=std::pair,_Allocator=std::Allocator,_ExtractKey=std::_Select1st,_Equal=std::Equal::to,_H1=std::hash,_H2=std:_detail:_Mod_range_散列,_hash=std:_Default_ranged_散列,_RehashPolicy=std:u detail:u Prime:u Prime\rehash\uu策略,bool\uu缓存,bool\uu代码,bool=false,fou常量迭代器l_uuuunique_keys=true,std::Hashtable::u Node=std:uuu detail:Hash_Node,std:Hashtable:Hashtable:u type=Node,typename std:Hashtable:Hash_code=long unsigned int]'
/usr/include/c++/4.6/bits/hashtable_policy.h:546:53:实例化自'std::_-Map_-base::mapped_-type&std:::_-detail:::_-Map_-base::operator[](const-Key&)[带_-Key=Node,_-Pair=std::Pair,_-hashtable=std:_-std:_-hashtable:(hashtable:)mapped:_-base:(mapped)Map)mapped)base:40
3sum.cpp:149:5:从此处实例化
/usr/include/c++/4.6/bits/stl_function.h:209:23:错误:将'const Node'作为'bool Node::operator==(Node)'的'this'参数传递将丢弃限定符[-fppermissive]
make:**[threeSum]错误1
我想,我需要告诉C++如何散列类<代码>节点< /> >,但是,我不太确定怎么做。我如何才能完成这个任务?
< p>能够使用<代码> STD::unOrdEdEdMult//Cu>(或者是其他无序的关联容器)中的一个用户定义的键类型,你需要定义两件事:
一个散列函数;该类必须重写操作符()
,并计算给定键类型对象的散列值。一种特别简单的方法是专门化键类型的std::hash
模板
相等的比较函数;这是必需的,因为哈希函数不能依赖于哈希函数始终为每个不同的键提供唯一的哈希值这一事实(即,它需要能够处理冲突),因此它需要一种方法来比较两个给定的键以获得精确的匹配。您可以将其实现为重写操作符()
,或作为std::equal
的专门化,或者–最简单的–为您的键类型重载操作符==()
哈希函数的困难在于,如果密钥类型由多个成员组成,则通常会让哈希函数为各个成员计算哈希值,然后以某种方式将它们组合为整个对象的一个哈希值。为了获得良好的性能(即,很少发生冲突)您应该仔细考虑如何组合各个散列值,以确保避免经常为不同的对象获得相同的输出
哈希函数的一个相当好的起点是使用位移位和按位异或来组合各个哈希值。例如,假设密钥类型如下:
struct Key
{
std::string first;
std::string second;
int third;
bool operator==(const Key &other) const
{ return (first == other.first
&& second == other.second
&& third == other.third);
}
};
下面是一个简单的散列函数(改编自中使用的散列函数):
它将自动使用上文定义的std::hash
进行散列值计算,并将运算符==
定义为键的成员函数进行相等性检查
如果您不想在std
命名空间内专门化模板(尽管在这种情况下完全合法),可以将哈希函数定义为单独的类,并将其添加到映射的模板参数列表中:
struct KeyHasher
{
std::size_t operator()(const Key& k) const
{
using std::size_t;
using std::hash;
using std::string;
return ((hash<string>()(k.first)
^ (hash<string>()(k.second) << 1)) >> 1)
^ (hash<int>()(k.third) << 1);
}
};
int main()
{
std::unordered_map<Key,std::string,KeyHasher> m6 = {
{ {"John", "Doe", 12}, "example"},
{ {"Mary", "Sue", 21}, "another"}
};
}
这里有一个重写,它不使用boost,但使用了很好的哈希组合方法:
namespace std
{
template <>
struct hash<Key>
{
size_t operator()( const Key& k ) const
{
// Compute individual hash values for first, second and third
// http://stackoverflow.com/a/1646913/126995
size_t res = 17;
res = res * 31 + hash<string>()( k.first );
res = res * 31 + hash<string>()( k.second );
res = res * 31 + hash<int>()( k.third );
return res;
}
};
}
名称空间std
{
样板
结构散列
{
大小\u t运算符()(常数键和k)常数
{
//计算第一个、第二个和第三个的散列值
// http://stackoverflow.com/a/1646913/126995
尺寸=17;
res=res*31+hash()(k.first);
res=res*31+hash()(k秒);
res=res*31+hash()(k.third);
返回res;
struct KeyHasher
{
std::size_t operator()(const Key& k) const
{
using std::size_t;
using std::hash;
using std::string;
return ((hash<string>()(k.first)
^ (hash<string>()(k.second) << 1)) >> 1)
^ (hash<int>()(k.third) << 1);
}
};
int main()
{
std::unordered_map<Key,std::string,KeyHasher> m6 = {
{ {"John", "Doe", 12}, "example"},
{ {"Mary", "Sue", 21}, "another"}
};
}
#include <boost/functional/hash.hpp>
struct KeyHasher
{
std::size_t operator()(const Key& k) const
{
using boost::hash_value;
using boost::hash_combine;
// Start with a hash value of 0 .
std::size_t seed = 0;
// Modify 'seed' by XORing and bit-shifting in
// one member of 'Key' after the other:
hash_combine(seed,hash_value(k.first));
hash_combine(seed,hash_value(k.second));
hash_combine(seed,hash_value(k.third));
// Return the result.
return seed;
}
};
namespace std
{
template <>
struct hash<Key>
{
size_t operator()( const Key& k ) const
{
// Compute individual hash values for first, second and third
// http://stackoverflow.com/a/1646913/126995
size_t res = 17;
res = res * 31 + hash<string>()( k.first );
res = res * 31 + hash<string>()( k.second );
res = res * 31 + hash<int>()( k.third );
return res;
}
};
}
using h = std::hash<int>;
auto hash = [](const Node& n){return ((17 * 31 + h()(n.a)) * 31 + h()(n.b)) * 31 + h()(n.c);};
auto equal = [](const Node& l, const Node& r){return l.a == r.a && l.b == r.b && l.c == r.c;};
std::unordered_map<Node, int, decltype(hash), decltype(equal)> m(8, hash, equal);
template <typename T>
struct EnumTypeHash {
std::size_t operator()(const T& type) const {
return static_cast<std::size_t>(type);
}
};
enum MyEnum {};
class MyValue {};
std::unordered_map<MyEnum, MyValue, EnumTypeHash<MyEnum>> map_;
// UnorderedMapObjectAsKey.cpp
#include <iostream>
#include <vector>
#include <unordered_map>
struct Pos
{
int row;
int col;
Pos() { }
Pos(int row, int col)
{
this->row = row;
this->col = col;
}
bool operator==(const Pos& otherPos) const
{
if (this->row == otherPos.row && this->col == otherPos.col) return true;
else return false;
}
struct HashFunction
{
size_t operator()(const Pos& pos) const
{
size_t rowHash = std::hash<int>()(pos.row);
size_t colHash = std::hash<int>()(pos.col) << 1;
return rowHash ^ colHash;
}
};
};
int main(void)
{
std::unordered_map<Pos, int, Pos::HashFunction> umap;
// at row 1, col 2, set value to 5
umap[Pos(1, 2)] = 5;
// at row 3, col 4, set value to 10
umap[Pos(3, 4)] = 10;
// print the umap
std::cout << "\n";
for (auto& element : umap)
{
std::cout << "( " << element.first.row << ", " << element.first.col << " ) = " << element.second << "\n";
}
std::cout << "\n";
return 0;
}