C++ STL unordered_map容器用法詳解


C++ STL 標准庫中提供有 4 種無序關聯式容器,本節先講解 unordered_map 容器。

unordered_map 容器,直譯過來就是"無序 map 容器"的意思。所謂“無序”,指的是 unordered_map 容器不會像 map 容器那樣對存儲的數據進行排序。換句話說,unordered_map 容器和 map 容器僅有一點不同,即 map 容器中存儲的數據是有序的,而 unordered_map 容器中是無序的。

 

具體來講,unordered_map 容器和 map 容器一樣,以鍵值對(pair類型)的形式存儲數據,存儲的各個鍵值對的鍵互不相同且不允許被修改。但由於 unordered_map 容器底層采用的是哈希表存儲結構,該結構本身不具有對數據的排序功能,所以此容器內部不會自行對存儲的鍵值對進行排序。

 

值得一提的是,unordered_map 容器在<unordered_map>頭文件中,並位於 std 命名空間中。因此,如果想使用該容器,代碼中應包含如下語句:

    1. #include <unordered_map>
    2. 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{

{"Python教程","http://c.biancheng.net/python/"},

{"Java教程","http://c.biancheng.net/java/"},

{"Linux教程","http://c.biancheng.net/linux/"} };

通過此方法創建的 umap 容器中,就包含有 3 個鍵值對元素。

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教程","http://c.biancheng.net/python/"},

{"Java教程","http://c.biancheng.net/java/"},

{"Linux教程","http://c.biancheng.net/linux/"} };

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 類模板提供的所有常用的成員方法以及各自的功能。

表 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() 非成員函數。


下面的樣例演示了表 2 中部分成員方法的用法:

 

#include <iostream>

#include <string>

#include <unordered_map>

using namespace std;

int main()

{

//創建空 umap 容器

unordered_map<string, string> umap;

//向 umap 容器添加新鍵值對

umap.emplace("Python教程", "http://c.biancheng.net/python/");

umap.emplace("Java教程", "http://c.biancheng.net/java/");

umap.emplace("Linux教程", "http://c.biancheng.net/linux/");

  1. //輸出 umap 存儲鍵值對的數量
  2. cout << "umap size = " << umap.size() << endl;
  3. //使用迭代器輸出 umap 容器存儲的所有鍵值對
  4. for (auto iter = umap.begin(); iter != umap.end(); ++iter) {
  5. cout << iter->first << " " << iter->second << endl;
  6. }
  7. return 0;
  8. }

程序執行結果為:

umap size = 3
Python教程 http://c.biancheng.net/python/
Linux教程 http://c.biancheng.net/linux/
Java教程 http://c.biancheng.net/java/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM