C++ STL之unordered_map
unordered_map 容器,直譯過來就是"無序 map 容器"的意思。所謂“無序”,指的是 unordered_map 容器不會像 map 容器那樣對儲存的資料進行排序。換句話說,unordered_map 容器和 map 容器僅有一點不同,即 map 容器中儲存的資料是有序的,而 unordered_map 容器中是無序的。
對於已經學過 map 容器的讀者,可以將 unordered_map 容器等價為無序的 map 容器。
具體來講,unordered_map 容器和 map 容器一樣,以鍵值對(pair型別)的形式儲存資料,儲存的各個鍵值對的鍵互不相同且不允許被修改。但由於 unordered_map 容器底層採用的是雜湊表儲存結構,該結構本身不具有對資料的排序功能,所以此容器內部不會自行對儲存的鍵值對進行排序。
值得一提的是,unordered_map 容器在<unordered_map>
#include <unordered_map>
using namespace std;
unordered_map 容器模板的定義如下所示:
template < class Key, //鍵值對中鍵的型別 class T, //鍵值對中值的型別 class Hash = hash<Key>, //容器內部儲存鍵值對所用的雜湊函式 class Pred = equal_to<Key>, //判斷各個鍵值對鍵相同的規則 class Alloc = allocator< pair<const Key,T> > // 指定分配器物件的型別 > class unordered_map;
以上 5 個引數中,必須顯式給前 2 個引數傳值,並且除特殊情況外,最多隻需要使用前 4 個引數,各自的含義和功能如表 1 所示。
引數 | 含義 |
---|---|
<key,T> | 前 2 個引數分別用於確定鍵值對中鍵和值的型別,也就是儲存鍵值對的型別。 |
Hash = hash<Key> | 用於指明容器在儲存各個鍵值對時要使用的雜湊函式,預設使用 STL 標準庫提供的 hash<key> 雜湊函式。注意,預設雜湊函式只適用於基本資料型別(包括 string 型別),而不適用於自定義的結構體或者類。 |
Pred = equal_to<Key> | 要知道,unordered_map 容器中儲存的各個鍵值對的鍵是不能相等的,而判斷是否相等的規則,就由此引數指定。預設情況下,使用 STL 標準庫中提供的 equal_to<key> 規則,該規則僅支援可直接用 == 運算子做比較的資料型別。 |
總的來說,當無序容器中儲存鍵值對的鍵為自定義型別時,預設的雜湊函式 hash 以及比較函式 equal_to 將不再適用,只能自己設計適用該型別的雜湊函式和比較函式,並顯式傳遞給 Hash 引數和 Pred 引數。至於如何實現自定義,後續章節會做詳細講解。
建立C++ unordered_map容器的方法
常見的建立 unordered_map 容器的方法有以下幾種。
1) 通過呼叫 unordered_map 模板類的預設建構函式,可以建立空的 unordered_map 容器。比如:
std::unordered_map<std::string, std::string> umap;
由此,就建立好了一個可儲存 <string,string> 型別鍵值對的 unordered_map 容器。
2) 當然,在建立 unordered_map 容器的同時,可以完成初始化操作。比如:
std::unordered_map<std::string, std::string> umap{
{"aaa","aaa"},
{"bbb","bbb"} };
通過此方法建立的 umap 容器中,就包含有 2 個鍵值對元素。
3) 另外,還可以呼叫 unordered_map 模板中提供的複製(拷貝)建構函式,將現有 unordered_map 容器中儲存的鍵值對,複製給新建 unordered_map 容器。
例如,在第二種方式建立好 umap 容器的基礎上,再建立並初始化一個 umap2 容器:
- std::unordered_map<std::string, std::string> umap2(umap);
由此,umap2 容器中就包含有 umap 容器中所有的鍵值對。
除此之外,C++ 11 標準中還向 unordered_map 模板類增加了移動建構函式,即以右值引用的方式將臨時 unordered_map 容器中儲存的所有鍵值對,全部複製給新建容器。例如:
//返回臨時 unordered_map 容器的函式
std::unordered_map <std::string, std::string > retUmap(){
std::unordered_map<std::string, std::string>tempUmap{
{"Python","易用"},
{"Java教程","流行"}};
return tempUmap;
}
//呼叫移動建構函式,建立 umap2 容器
std::unordered_map<std::string, std::string> umap2(retUmap());
注意,無論是呼叫複製建構函式還是拷貝建構函式,必須保證 2 個容器的型別完全相同。
4) 當然,如果不想全部拷貝,可以使用 unordered_map 類模板提供的迭代器,在現有 unordered_map 容器中選擇部分割槽域內的鍵值對,為新建 unordered_map 容器初始化。例如:
- //傳入 2 個迭代器,
- std::unordered_map<std::string, std::string> umap2(++umap.begin(),umap.end());
通過此方式建立的 umap2 容器,其內部就包含 umap 容器中除第 1 個鍵值對外的所有其它鍵值對。
C++ unordered_map容器的成員方法
unordered_map 既可以看做是關聯式容器,更屬於自成一脈的無序容器。因此在該容器模板類中,既包含一些在學習關聯式容器時常見的成員方法,還有一些屬於無序容器特有的成員方法。
表 2 列出了 unordered_map 類模板提供的所有常用的成員方法以及各自的功能。
成員方法 | 功能 |
---|---|
begin() | 返回指向容器中第一個鍵值對的正向迭代器。 |
end() | 返回指向容器中最後一個鍵值對之後位置的正向迭代器。 |
cbegin() | 和 begin() 功能相同,只不過在其基礎上增加了 const 屬性,即該方法返回的迭代器不能用於修改容器記憶體儲的鍵值對。 |
cend() | 和 end() 功能相同,只不過在其基礎上,增加了 const 屬性,即該方法返回的迭代器不能用於修改容器記憶體儲的鍵值對。 |
empty() | 若容器為空,則返回 true;否則 false。 |
size() | 返回當前容器中存有鍵值對的個數。 |
max_size() | 返回容器所能容納鍵值對的最大個數,不同的作業系統,其返回值亦不相同。 |
operator[key] | 該模板類中過載了 [] 運算子,其功能是可以向訪問陣列中元素那樣,只要給定某個鍵值對的鍵 key,就可以獲取該鍵對應的值。注意,如果當前容器中沒有以 key 為鍵的鍵值對,則其會使用該鍵向當前容器中插入一個新鍵值對。 |
at(key) | 返回容器中儲存的鍵 key 對應的值,如果 key 不存在,則會丟擲 out_of_range 異常。 |
find(key) | 查詢以 key 為鍵的鍵值對,如果找到,則返回一個指向該鍵值對的正向迭代器;反之,則返回一個指向容器中最後一個鍵值對之後位置的迭代器(如果 end() 方法返回的迭代器)。 |
count(key) | 在容器中查詢以 key 鍵的鍵值對的個數。 |
equal_range(key) | 返回一個 pair 物件,其包含 2 個迭代器,用於表明當前容器中鍵為 key 的鍵值對所在的範圍。 |
emplace() | 向容器中新增新鍵值對,效率比 insert() 方法高。 |
emplace_hint() | 向容器中新增新鍵值對,效率比 insert() 方法高。 |
insert() | 向容器中新增新鍵值對。 |
erase() | 刪除指定鍵值對。 |
clear() | 清空容器,即刪除容器中儲存的所有鍵值對。 |
swap() | 交換 2 個 unordered_map 容器儲存的鍵值對,前提是必須保證這 2 個容器的型別完全相等。 |
bucket_count() | 返回當前容器底層儲存鍵值對時,使用桶(一個線性連結串列代表一個桶)的數量。 |
max_bucket_count() | 返回當前系統中,unordered_map 容器底層最多可以使用多少桶。 |
bucket_size(n) | 返回第 n 個桶中儲存鍵值對的數量。 |
bucket(key) | 返回以 key 為鍵的鍵值對所在桶的編號。 |
load_factor() | 返回 unordered_map 容器中當前的負載因子。負載因子,指的是的當前容器中儲存鍵值對的數量(size())和使用桶數(bucket_count())的比值,即 load_factor() = size() / bucket_count()。 |
max_load_factor() | 返回或者設定當前 unordered_map 容器的負載因子。 |
rehash(n) | 將當前容器底層使用桶的數量設定為 n。 |
reserve() | 將儲存桶的數量(也就是 bucket_count() 方法的返回值)設定為至少容納count個元(不超過最大負載因子)所需的數量,並重新整理容器。 |
hash_function() | 返回當前容器使用的雜湊函式物件。 |
注意,對於實現互換 2 個相同型別 unordered_map 容器的鍵值對,除了可以呼叫該容器模板類中提供的 swap() 成員方法外,STL 標準庫還提供了同名的 swap() 非成員函式。