STL: unordered_map 自定义键值类型的使用(C++)

当试图使用自定义类型作为 unordered_map 的键值时,则必须为自定义类型定义 Hash 函数与相等的判断条件。我们先定义自定义类型作键值,代码如下:

 

[cpp] view plain copy
 
  1. struct KEY  
  2. {  
  3.     int first;  
  4.     int second;  
  5.     int third;  
  6.   
  7.     KEY(int f, int s, int t) : first(f), second(s), third(t){}  
  8. };  

 

    1. Hash 函数

    必须为 override 了 operator() 的一个类,一般自定义类型可能包含几种内置类型,我们可以分别计算出内置类型的 Hash Value 然后对它们进行 Combine 得到一个哈希值,一般直接采用移位加异或(XOR)便可得到还不错的哈希值(碰撞不会太频繁),如下:

 

[cpp] view plain copy
 
  1. struct HashFunc  
  2. {  
  3.     std::size_t operator()(const KEY &key) const   
  4.     {  
  5.         using std::size_t;  
  6.         using std::hash;  
  7.   
  8.         return ((hash<int>()(key.first)  
  9.             ^ (hash<int>()(key.second) << 1)) >> 1)  
  10.             ^ (hash<int>()(key.third) << 1);  
  11.     }  
  12. };  

 

    另外一种方法是直接实例化模板,这样的话使用 unordered_map 时便不用再指定 Hash 函数,但要求必须为 KEY 重载 operator ==,实例化模板如下:

 

[cpp] view plain copy
 
  1. namespace std   
  2. {  
  3.     template <>  
  4.     struct hash<KEY>  
  5.     {  
  6.         std::size_t operator()(const KEY &key) const  
  7.         {  
  8.             using std::size_t;  
  9.             using std::hash;  
  10.   
  11.             // Compute individual hash values for first,  
  12.             // second and third and combine them using XOR  
  13.             // and bit shifting:  
  14.   
  15.             return ((hash<int>()(key.first)  
  16.                 ^ (hash<int>()(key.second) << 1)) >> 1)  
  17.                 ^ (hash<int>()(key.third) << 1);  
  18.         }  
  19.     };  
  20. }  

 

    2. 相等函数

    哈希需要处理碰撞,意味着必须得知道两个自定义类型对象是否相等,所以必须得提供比较相等的方法,可以 overload operator ==,可以用 std::equal,也可以实现一个 override operator () 的类,这里我们采用后者(这也意味着 Hash 函数不能使用实例化模板的方法,只能定义一个重载了 operator() 的类),代码如下:

 

[cpp] view plain copy
 
  1. struct EqualKey  
  2. {  
  3.     bool operator () (const KEY &lhs, const KEY &rhs) const  
  4.     {  
  5.         return lhs.first  == rhs.first  
  6.             && lhs.second == rhs.second  
  7.             && lhs.third  == rhs.third;  
  8.     }  
  9. };  

 

    3. 应用实例

    下面为一个具体应用的例子

 

[cpp] view plain copy
 
  1. int main()  
  2. {  
  3.     unordered_map<KEY, string, HashFunc, EqualKey> hashmap =  
  4.     {  
  5.         { { 01, 02, 03 }, "one" },  
  6.         { { 11, 12, 13 }, "two" },  
  7.         { { 21, 22, 23 }, "three" },  
  8.     };  
  9.   
  10.     KEY key(11, 12, 13);  
  11.   
  12.     auto it = hashmap.find(key);  
  13.       
  14.     if (it != hashmap.end())  
  15.     {  
  16.         cout << it->second << endl;  
  17.     }  
  18.   
  19.     return 0;  
  20. }  

 

 
 
posted @ 2017-03-29 13:37  crazy_machine  阅读(1316)  评论(0)    收藏  举报