作爲關聯式容器的一種,map 容器存儲的都是 pair 對象,也就是用 pair 類模板創建的鍵值對。其中,各個鍵值對的鍵和值可以是任意數據類型,包括 C++ 基本數據類型(int、double 等)、使用結構體或類自定義的類型。
與此同時,在使用 map 容器存儲多個鍵值對時,該容器會自動根據各鍵值對的鍵的大小,按照既定的規則進行排序。默認情況下,map 容器選用std::less<T>
排序規則(其中 T 表示鍵的數據類型),其會根據鍵的大小對所有鍵值對做升序排序。當然,根據實際情況的需要,我們可以手動指定 map 容器的排序規則,既可以選用 STL 標準庫中提供的其它排序規則(比如std::greater<T>
),也可以自定義排序規則。
另外需要注意的是,使用 map 容器存儲的各個鍵值對,鍵的值既不能重複也不能被修改。換句話說,map 容器中存儲的各個鍵值對不僅鍵的值獨一無二,鍵的類型也會用 const 修飾,這意味着只要鍵值對被存儲到 map 容器中,其鍵的值將不能再做任何修改。
std::pair
std::pair 是一個結構體模板,其可於一個單元內存儲兩個相異對象。是 std::tuple 的擁有兩個元素的特殊情況。
一般來說,pair 可以封裝任意類型的對象,可以生成各種不同的 std::pair<T1, T2> 對象,可以是數組對象或者包含 std::pair<T1,T2> 的 vector 容器。pair 還可以封裝兩個序列容器或兩個序列容器的指針。
1. 定義
#include <utility> template<class T1, class T2> struct pair;模板參數 T1 和 T2 是 pair 所存儲的元素的類型。
包含有兩個成員變量 first 和 second,而且都是 public 修飾的,通過 "." 訪問。
其中 first 類型爲T1, second 類型爲T2。
1 pair的應用
pair是將2個數據組合成一個數據,當需要這樣的需求時就可以使用pair,如stl中的map就是將key和value放在一起來保存。另一個應用是,當一個函數需要返回2個數據的時候,可以選擇pair。 pair的實現是一個結構體,主要的兩個成員變量是first second 因爲是使用struct不是class,所以可以直接使用pair的成員變量。
2 make_pair函數
template pair make_pair(T1 a, T2 b) { return pair(a, b); }
很明顯,我們可以使用pair的構造函數也可以使用make_pair來生成我們需要的pair。 一般make_pair都使用在需要pair做參數的位置,可以直接調用make_pair生成pair對象很方便,代碼也很清晰。 另一個使用的方面就是pair可以接受隱式的類型轉換,這樣可以獲得更高的靈活度。靈活度也帶來了一些問題如:
std::pair<int, float>(1, 1.1);
std::make_pair(1, 1.1);
是不同的,第一個就是float,而第2個會自己匹配成double。
類模板:template <class T1, class T2> struct pair
參數:T1是第一個值的數據類型,T2是第二個值的數據類型。
功能:pair將一對值組合成一個值,這一對值可以具有不同的數據類型(T1和T2),兩個值可以分別用pair的兩個公有函數first和second訪問。
具體用法:
1.定義(構造):
1 pair<int, double> p1; //使用默認構造函數
2 pair<int, double> p2(1, 2.4); //用給定值初始化
3 pair<int, double> p3(p2); //拷貝構造函數
2.訪問兩個元素(通過first和second):
1 pair<int, double> p1; //使用默認構造函數
2 p1.first = 1;
3 p1.second = 2.5;
4 cout << p1.first << ' ' << p1.second << endl;
輸出結果:1 2.5
創建C++ map容器的幾種方法
map 容器的模板類中包含多種構造函數,因此創建 map 容器的方式也有多種,下面就幾種常用的創建 map 容器的方法,做一一講解。
1) 通過調用 map 容器類的默認構造函數,可以創建出一個空的 map 容器,比如:
std::map<std::string, int>myMap;
通過此方式創建出的 myMap 容器,初始狀態下是空的,即沒有存儲任何鍵值對。鑑於空 map 容器可以根據需要隨時添加新的鍵值對,因此創建空 map 容器是比較常用的。
2) 當然在創建 map 容器的同時,也可以進行初始化,比如:
std::map<std::string, int>myMap{ {"C語言教程",10},{"STL教程",20} };
由此,myMap 容器在初始狀態下,就包含有 2 個鍵值對。
再次強調,map 容器中存儲的鍵值對,其本質都是 pair 類模板創建的 pair 對象。因此,下面程序也可以創建出一模一樣的 myMap 容器:
std::map<std::string, int>myMap{std::make_pair("C語言教程",10),std::make_pair("STL教程",20)};
3) 除此之外,在某些場景中,可以利用先前已創建好的 map 容器,再創建一個新的 map 容器。例如:
std::map<std::string, int>newMap(myMap);
由此,通過調用 map 容器的拷貝(複製)構造函數,即可成功創建一個和 myMap 完全一樣的 newMap 容器。
C++ 11 標準中,還爲 map 容器增添了移動構造函數。當有臨時的 map 對象作爲參數,傳遞給要初始化的 map 容器時,此時就會調用移動構造函數。舉個例子:
#創建一個會返回臨時 map 對象的函數
std::map<std::string,int> disMap() {
std::map<std::string, int>tempMap{ {"C語言教程",10},{"STL教程",20} };
return tempMap;
}
//調用 map 類模板的移動構造函數創建 newMap 容器
std::map<std::string, int>newMap(disMap());
4) map 類模板還支持取已建 map 容器中指定區域內的鍵值對,創建並初始化新的 map 容器。例如:
std::map<std::string, int>myMap{ {"C語言教程",10},{"STL教程",20} };
std::map<std::string, int>newMap(++myMap.begin(), myMap.end());
5) 當然,在以上幾種創建 map 容器的基礎上,我們都可以手動修改 map 容器的排序規則。默認情況下,map 容器調用 std::less<T> 規則,根據容器內各鍵值對的鍵的大小,對所有鍵值對做升序排序。
因此,如下 2 行創建 map 容器的方式,其實是等價的:
std::map<std::string, int>myMap{ {"C語言教程",10},{"STL教程",20} };
std::map<std::string, int, std::less<std::string> >myMap{ {"C語言教程",10},{"STL教程",20} };
以上 2 中創建方式生成的 myMap 容器,其內部鍵值對排列的順序爲:
<"C語言教程", 10>
<"STL教程", 20>
下面程序手動修改了 myMap 容器的排序規則,令其作降序排序:
std::map<std::string, int, std::greater<std::string> >myMap{ {"C語言教程",10},{"STL教程",20} };
此時,myMap 容器內部鍵值對排列的順序爲:
<"STL教程", 20>
<"C語言教程", 10>
C++ map容器包含的成員方法
成員方法 | 功能 |
---|---|
begin() | 返回指向容器中第一個(注意,是已排好序的第一個)鍵值對的雙向迭代器。如果 map 容器用 const 限定,則該方法返回的是 const 類型的雙向迭代器。 |
end() | 返回指向容器最後一個元素(注意,是已排好序的最後一個)所在位置後一個位置的雙向迭代器,通常和 begin() 結合使用。如果 map 容器用 const 限定,則該方法返回的是 const 類型的雙向迭代器。 |
rbegin() | 返回指向最後一個(注意,是已排好序的最後一個)元素的反向雙向迭代器。如果 map 容器用 const 限定,則該方法返回的是 const 類型的反向雙向迭代器。 |
rend() | 返回指向第一個(注意,是已排好序的第一個)元素所在位置前一個位置的反向雙向迭代器。如果 map 容器用 const 限定,則該方法返回的是 const 類型的反向雙向迭代器。 |
cbegin() | 和 begin() 功能相同,只不過在其基礎上,增加了 const 屬性,不能用於修改容器內存儲的鍵值對。 |
cend() | 和 end() 功能相同,只不過在其基礎上,增加了 const 屬性,不能用於修改容器內存儲的鍵值對。 |
crbegin() | 和 rbegin() 功能相同,只不過在其基礎上,增加了 const 屬性,不能用於修改容器內存儲的鍵值對。 |
crend() | 和 rend() 功能相同,只不過在其基礎上,增加了 const 屬性,不能用於修改容器內存儲的鍵值對。 |
find(key) | 在 map 容器中查找鍵爲 key 的鍵值對,如果成功找到,則返回指向該鍵值對的雙向迭代器;反之,則返回和 end() 方法一樣的迭代器。另外,如果 map 容器用 const 限定,則該方法返回的是 const 類型的雙向迭代器。 |
lower_bound(key) | 返回一個指向當前 map 容器中第一個大於或等於 key 的鍵值對的雙向迭代器。如果 map 容器用 const 限定,則該方法返回的是 const 類型的雙向迭代器。 |
upper_bound(key) | 返回一個指向當前 map 容器中第一個大於 key 的鍵值對的迭代器。如果 map 容器用 const 限定,則該方法返回的是 const 類型的雙向迭代器。 |
equal_range(key) | 該方法返回一個 pair 對象(包含 2 個雙向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等價,pair.second 和 upper_bound() 方法的返回值等價。也就是說,該方法將返回一個範圍,該範圍中包含的鍵爲 key 的鍵值對(map 容器鍵值對唯一,因此該範圍最多包含一個鍵值對)。 |
empty() | 若容器爲空,則返回 true;否則 false。 |
size() | 返回當前 map 容器中存有鍵值對的個數。 |
max_size() | 返回 map 容器所能容納鍵值對的最大個數,不同的操作系統,其返回值亦不相同。 |
operator[] | map容器重載了 [] 運算符,只要知道 map 容器中某個鍵值對的鍵的值,就可以向獲取數組中元素那樣,通過鍵直接獲取對應的值。 |
at(key) | 找到 map 容器中 key 鍵對應的值,如果找不到,該函數會引發 out_of_range 異常。 |
insert() | 向 map 容器中插入鍵值對。 |
erase() | 刪除 map 容器指定位置、指定鍵(key)值或者指定區域內的鍵值對。後續章節還會對該方法做重點講解。 |
swap() | 交換 2 個 map 容器中存儲的鍵值對,這意味着,操作的 2 個鍵值對的類型必須相同。 |
clear() | 清空 map 容器中所有的鍵值對,即使 map 容器的 size() 爲 0。 |
emplace() | 在當前 map 容器中的指定位置處構造新鍵值對。其效果和插入鍵值對一樣,但效率更高。 |
emplace_hint() | 在本質上和 emplace() 在 map 容器中構造新鍵值對的方式是一樣的,不同之處在於,使用者必須爲該方法提供一個指示鍵值對生成位置的迭代器,並作爲該方法的第一個參數。 |
count(key) | 在當前 map 容器中,查找鍵爲 key 的鍵值對的個數並返回。注意,由於 map 容器中各鍵值對的鍵的值是唯一的,因此該函數的返回值最大爲 1。 |