當試圖使用自定義類型作爲 unordered_map 的鍵值時,則必須爲自定義類型定義 Hash 函數與相等的判斷條件。我們先定義自定義類型作鍵值,代碼如下:
struct KEY
{
int first;
int second;
int third;
KEY(int f, int s, int t) : first(f), second(s), third(t){}
};
1. Hash 函數
必須爲 override 了 operator() 的一個類,一般自定義類型可能包含幾種內置類型,我們可以分別計算出內置類型的 Hash Value 然後對它們進行 Combine 得到一個哈希值,一般直接採用移位加異或(XOR)便可得到還不錯的哈希值(碰撞不會太頻繁),如下:
struct HashFunc
{
std::size_t operator()(const KEY &key) const
{
using std::size_t;
using std::hash;
return ((hash<int>()(key.first)
^ (hash<int>()(key.second) << 1)) >> 1)
^ (hash<int>()(key.third) << 1);
}
};
另外一種方法是直接實例化模板,這樣的話使用 unordered_map 時便不用再指定 Hash 函數,但要求必須爲 KEY 重載 operator ==,實例化模板如下:
namespace std
{
template <>
struct hash<KEY>
{
std::size_t operator()(const KEY &key) const
{
using std::size_t;
using std::hash;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<int>()(key.first)
^ (hash<int>()(key.second) << 1)) >> 1)
^ (hash<int>()(key.third) << 1);
}
};
}
2. 相等函數
哈希需要處理碰撞,意味着必須得知道兩個自定義類型對象是否相等,所以必須得提供比較相等的方法,可以 overload operator ==,可以用 std::equal,也可以實現一個 override operator () 的類,這裏我們採用後者(這也意味着 Hash 函數不能使用實例化模板的方法,只能定義一個重載了 operator() 的類),代碼如下:
struct EqualKey
{
bool operator () (const KEY &lhs, const KEY &rhs) const
{
return lhs.first == rhs.first
&& lhs.second == rhs.second
&& lhs.third == rhs.third;
}
};
3. 應用實例
下面爲一個具體應用的例子
int main()
{
unordered_map<KEY, string, HashFunc, EqualKey> hashmap =
{
{ { 01, 02, 03 }, "one" },
{ { 11, 12, 13 }, "two" },
{ { 21, 22, 23 }, "three" },
};
KEY key(11, 12, 13);
auto it = hashmap.find(key);
if (it != hashmap.end())
{
cout << it->second << endl;
}
return 0;
}