1. 程式人生 > 其它 >C++ STL之unordered_map

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>

標頭檔案中,並位於 std 名稱空間中。因此,如果想使用該容器,程式碼中應包含如下語句:

#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 所示。

表 1 unordered_map 容器模板類的常用引數
引數 含義
<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 容器:

  1. 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 容器初始化。例如:

  1. //傳入 2 個迭代器,
  2. std::unordered_map<std::string, std::string> umap2(++umap.begin(),umap.end());

通過此方式建立的 umap2 容器,其內部就包含 umap 容器中除第 1 個鍵值對外的所有其它鍵值對。

C++ unordered_map容器的成員方法

unordered_map 既可以看做是關聯式容器,更屬於自成一脈的無序容器。因此在該容器模板類中,既包含一些在學習關聯式容器時常見的成員方法,還有一些屬於無序容器特有的成員方法。

表 2 列出了 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() 非成員函式。