To be able to use std::unordered_map (or one of the other unordered associative containers) with a user-defined key-type, you need to define two things:
A fairly good starting point for a hash function is one that uses bit shifting and bitwise XOR to combine the individual hash values. For example, assuming a key-type like this:
With this in place, you can instantiate astruct 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); } };Here is a simple hash function (adapted from the one used in the cppreference example for user-defined hash functions): std::unordered_map for the key-type:int main() { std::unordered_map<Key,std::string> m6 = { { {"John", "Doe", 12}, "example"}, { {"Mary", "Sue", 21}, "another"} }; }It will automatically use std::hash as defined above for the hash value calculations, and the operator== defined as member function of Key for equality checks.If you don't want to specialize template inside the std
namespace (although it's perfectly legal in this case), you can define
the hash function as a separate class and add it to the template
argument list for the map:struct KeyHasher { std::size_t operator()(const Key& k) const { using std::size_t; using std::hash; using std::string; return ((hash()(k.first) ^ (hash()(k.second) << 1)) >> 1) ^ (hash()(k.third) << 1); } }; int main() { std::unordered_map<Key,std::string,KeyHasher> m6 = { { {"John", "Doe", 12}, "example"}, { {"Mary", "Sue", 21}, "another"} }; }How to define a better hash function? As said above, defining a good hash function is important to avoid collisions and get good performance. For a real good one you need to take into account the distribution of possible values of all fields and define a hash function that projects that distribution to a space of possible results as wide and evenly distributed as possible. This can be difficult; the XOR/bit-shifting method above is probably not a bad start. For a slightly better start, you may use the hash_value and hash_combine function template from the Boost library. The former acts in a similar way as std::hash
for standard types (recently also including tuples and other useful
standard types); the latter helps you combine individual hash values
into one. Here is a rewrite of the hash function that uses the Boost
helper functions:#include 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; } };And here’s a rewrite that doesn’t use boost, yet uses good method of combining the hashes: 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()( k.first ); res = res * 31 + hash()( k.second ); res = res * 31 + hash()( k.third ); return res; } }; } |
2016년 12월 24일 토요일
unordered_set / unordered_map with custom object in C++
http://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key
피드 구독하기:
댓글 (Atom)
sublime close without confirmation
Close without confirm Yes, you can just write a plugin to set the view as scratch and close it. Then create a keybinding for that c...
-
http://askubuntu.com/questions/21934/how-to-change-the-binding-of-windows-key-which-runs-unitys-dash just installed Ubuntu 11.04 and I w...
-
https://forums.virtualbox.org/viewtopic.php?t=11234 How to freeze date/time in VirtualBox? this can be achived by editi...
-
1 . download update 2. put a update file to localdata store directory 3 use command below esxcli software vib update -d "PATH TO A PATC...
댓글 없음:
댓글 쓰기