map 容器

作爲關聯式容器的一種,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。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章