用struct做unordered_map的key
本篇文章著重討論如何在STL的 unordered_map 中以 struct 作為 key.
unordered_map 是STL中的關聯容器,自然就是一個模板類。其宣告如下:
template < class Key, // unordered_map::key_type
class T, // unordered_map::mapped_type
class Hash = hash<Key>, // unordered_map::hasher
class Pred = equal_to<Key>, // unordered_map::key_equal
class Alloc = allocator< pair<const Key,T> > > class unordered_map;
// unordered_map::allocator_type
第1個引數是key的型別,第2個引數是value的型別,第5個是記憶體分配模型。關鍵是第3個引數和第4個引數。
第3個引數 Hash 是一個一元的函式物件型別;該函式物件只有一個引數,其型別是雜湊表的 Key 的型別。預設情況下,第3個引數傳入的是 std::hash<key> ,它返回的是一個型別為 size_t 的數字,用途是在雜湊表中定位表項所在。注意,若要自己實現第3個引數的話,首先它是一個型別(如struct),其次要實現這個型別的 operator() 方法。
那麼,當雜湊表發生衝突(即傳入2個不同的key,但 std::hash<key> 返回的是相同的數字)的時候怎麼辦呢?unordered_map作為STL中雜湊表的一種實現,它當然有辦法來解決衝突(如開式定址法或拉鍊法,這個要看STL中的具體實現);而我們得讓 unordered_map 能夠知道為什麼這2個key不一樣。這就是第4個引數的作用了。
第4個引數預設傳入的是 std::equal_to<key> 函式物件,它帶2個引數,也就是2個key例項,然後返回一個bool變數表示這2個key是否相等。使用者可以自己特化這個 equal_to 函式物件,但因為預設的 std::equal_to<key> 會去呼叫 key 型別的 operator == 函式,所以使用者其實只要實現 key 型別的 operator == 函式就可以了。
基於以上對於 unordered_map 的模板引數的分析,想把 struct或class 作為 unordered_map 的 key,就需要做以下2件事情。
1. 建立特化的 std::hash<Key> 函式,以便於根據Key型別的例項來獲得在雜湊表中的位置。(作為第4個引數)
2. 定義 operator == 以便於在 Hash 衝突時比較真正的key值是否相等。(operator == 被第3個引數預設的equal_to使用)
程式碼例項有2個。第1個請見上篇部落格中的程式碼。第2個程式碼例項如下:
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
template<typename T1, typename T2>
struct Node
{
T1 x;
T2 y;
Node(T1 a, T2 b) : x(a), y(b) {}
bool operator==(const Node& p) const {
return x == p.x && y == p.y;
}
};
// Way-1: specialized hash function for unordered_map keys
struct hash_fn
{
template <class T1, class T2>
std::size_t operator() (const Node<T1, T2> & node) const {
std::size_t h1 = std::hash<T1>()(node.x);
std::size_t h2 = std::hash<T2>()(node.y);
return h1 ^ h2;
}
};
// Way-2: 特化 std::hash<Node>
namespace std
{
template<typename T1, typename T2>
struct hash<Node<T1, T2>>
{
size_t operator() (const Node<T1, T2> & node) const noexcept
{
std::size_t h1 = std::hash<T1>()(node.x);
std::size_t h2 = std::hash<T2>()(node.y);
return h1 ^ h2;
}
};
}
int main()
{
// Way-1
std::unordered_map< Node<std::string,std::string>, int, hash_fn > u_map1 =
{
{{"C", "C99"}, 1999},
{{"C", "C11"}, 2011},
{{"C++", "C++14"}, 2014},
{{"C++", "C++17"}, 2017},
{{"Java", "Java SE 8"}, 2014},
{{"Java", "Java SE 9"}, 2017}
};
cout << "Way-1: \n";
for (const auto &entry: u_map1)
{
std::cout << "{" << entry.first.x << "," << entry.first.y << "}: "
<< entry.second << '\n';
}
// Way-2
std::unordered_map< Node<std::string,std::string>, int > u_map2 =
{
{{"C", "C99"}, 1999},
{{"C", "C11"}, 2011},
{{"C++", "C++14"}, 2014},
{{"C++", "C++17"}, 2017},
{{"Java", "Java SE 8"}, 2014},
{{"Java", "Java SE 9"}, 2017}
};
cout << "Way-2: \n";
for (const auto &entry: u_map2)
{
std::cout << "{" << entry.first.x << "," << entry.first.y << "}: "
<< entry.second << '\n';
}
return 0;
}
(完)
相關文章
- struct的tag到底可以用來做什麼?Struct
- 何時用 struct?何時用 class?Struct
- Cpp學習 -- <unordered_map>
- c++ unordered_map/set自定義物件的hashC++物件
- struct的一種用法Struct
- 陣列,map,unordered_map的簡單效能測試陣列
- c++ map和unordered_map比較C++
- unordered_map隨機底數種子隨機
- struct和typedef struct 有什麼不同呢?Struct
- Partition 表掃描的過程,使用key作為謂詞與使用非key值做謂詞....
- struct的匿名用法詳解Struct
- struct的拷貝問題Struct
- map、unordered_map、set 和 unordered_set的小介紹
- pat—結構體排序(用map彌補struct缺陷)結構體排序Struct
- Ruby Struct EqualStruct
- 結構 STRUCTStruct
- 詳解map、multimap、unordered_map、unordered_multimap
- With KEY & With Table KEY 的使用
- python模擬c的structPythonStruct
- 一個struct聚合的問題Struct
- union, struct, enum 的 大小區別Struct
- struct轉map (反射)Struct反射
- 結構體struct結構體Struct
- Struct與Class辨析Struct
- webservice中呼叫structWebStruct
- c#之structC#Struct
- keyup,keypress,keydown事件的區別事件
- Python中struct.pack()和struct.unpack()用法詳解PythonStruct
- 用 Roslyn 做個 JIT 的 AOPROS
- 用 API 做的 ServerSocket 例子 (轉)APIServer
- swift中Class和Struct的區別SwiftStruct
- 用SSH KEY遠端登入
- 關於c++ STL map 和 unordered_map 的效率的對比測試C++
- 用ollydbg破精誠MP3多功能播放器V2.0+用Keymake做註冊器 (906字)播放器
- C時間函式strftime、struct timespec 和 struct timeval函式Struct
- 結構struct(值型別)在實際應用中應該注意的點Struct型別
- C語言中 struct成員變數順序對記憶體的佔用C語言Struct變數記憶體
- RabbitMQ裡面的routingkey是幹嘛用的????????MQ