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 命名空間中。因此,如果想使用該容器,代碼中應包含如下語句:
- #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{
{"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/");
- //輸出 umap 存儲鍵值對的數量
- cout << "umap size = " << umap.size() << endl;
- //使用迭代器輸出 umap 容器存儲的所有鍵值對
- for (auto iter = umap.begin(); iter != umap.end(); ++iter) {
- cout << iter->first << " " << iter->second << endl;
- }
- return 0;
- }
程序執行結果為:
umap size = 3
Python教程 http://c.biancheng.net/python/
Linux教程 http://c.biancheng.net/linux/
Java教程 http://c.biancheng.net/java/