本篇將介紹如何使用 C++ std map 以及用法,C++ std::map 是一個關聯式容器,關聯式容器把鍵值和一個元素連繫起來,並使用該鍵值來尋找元素、插入元素和刪除元素等操作。
map 是有排序關聯式容器,即 map 容器中所有的元素都會根據元素對應的鍵值來排序,而鍵值 key 是唯一值,並不會出現同樣的鍵值 key,也就是說假設已經有一個 鍵值 key 存在 map 裡,當同樣的鍵值 key 再 insert 資料時,新的資料就會覆蓋掉原本 key 的資料。
map 的實作方式通常是用紅黑樹(red-black tree)實作的,這樣它可以保證可以在O(log n)
時間內完成搜尋、插入、刪除,n為元素的數目。
以下內容將分為這幾部分,
map 常用功能
map 初始化
map 容器插入元素與存取元素
map 容器的迴圈遍歷
使用 string 當 key 鍵值, int 當 value 資料的 map 範例
使用 string 當 key 鍵值, 自定義類別或自定義結構當 value 資料的 map 範例
刪除 map 指定的元素
清空 map 容器
判斷 map 容器是否為空
要使用 map 容器的話,需要引入的標頭檔 :<map>
map 常用功能 C++ map 是一種關聯式容器,包含「key鍵值/value資料」成對關係元素存取 operator[]
:存取指定的[i]元素的資料迭代器 begin()
:回傳指向map頭部元素的迭代器end()
:回傳指向map末尾的迭代器rbegin()
:回傳一個指向map尾部的反向迭代器rend()
:回傳一個指向map頭部的反向迭代器容量 empty()
:檢查容器是否為空,空則回傳truesize()
:回傳元素數量max_size()
:回傳可以容納的最大元素個數修改器 clear()
:刪除所有元素insert()
:插入元素erase()
:刪除一個元素swap()
:交換兩個map查找 count()
:回傳指定元素出現的次數find()
:查找一個元素
map 初始化 接下來說說怎麼初始化 c++ map 容器吧! 先以 int 當 key, string 當 value 的 map 為範例, 以一個班級的學生編號為例,一個編號會對應到一個學生,這邊先以學生姓名作示範, 所以會寫成std::map<int, std::string> studentMap
這樣 std::map 宣告時要宣告兩個變數類型, map.first:第一個稱為(key)鍵值,在 map 裡面,(key)鍵值不會重複 map.second:第二個稱為(key)鍵值對應的數值(value) map 容器初始化的寫法如下,1 2 3 4 std ::map <int , std ::string > studentMap;studentMap.insert(std ::pair<int , std ::string >(1 , "Tom" )); studentMap.insert(std ::pair<int , std ::string >(7 , "Jack" )); studentMap.insert(std ::pair<int , std ::string >(15 , "John" ));
或者像陣列的方式一樣1 2 3 4 std ::map <int , std ::string > studentMap;studentMap[1 ] = "Tom" ; studentMap[7 ] = "Jack" ; studentMap[15 ] = "John" ;
或者這樣初始化更專業一點1 2 3 4 5 std ::map <int , std ::string > studentMap = { {1 , "Tom" }, {2 , "Jack" }, {3 , "John" } };
map 容器插入元素與存取元素 剛剛在初始化部分已經有示範過了,map 容器插入元素有兩種寫法, 第一種是使用中括號 []
的方式來插入元素,很像陣列的寫法,例如:map[key] = value
,如果該 key 值已經存在則 value 會被更新成新的數值,範例如下,1 2 3 4 std ::map <int , std ::string > studentMap;studentMap[1 ] = "Tom" ; ... studentMap[1 ] = "John" ;
另一種是使用 map.insert()
成員函式來插入元素, 那這個 map.insert()
方式跟上面中括號 []
的方式有什麼不同呢?
差別在於如果 key 值已經存在的話,使用中括號 []
的方式會將新資料覆蓋舊資料, 而使用 map.insert()
的方式會回傳插入的結果,該 key 值存在的話會回傳失敗的結果, 檢查 map.insert()
的插入結果方式如下,std-map.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> #include <string> #include <map> int main () { std ::map <int , std ::string > studentMap; studentMap.insert(std ::pair<int , std ::string >(1 , "Tom" )); std ::pair<std ::map <int , std ::string >::iterator, bool > retPair; retPair = studentMap.insert(std ::pair<int , std ::string >(1 , "Tom" )); if (retPair.second == true ) std ::cout << "Insert Successfully\n" ; else std ::cout << "Insert Failure\n" ; return 0 ; }
要取得某 key 鍵值元素的話可以這樣寫,或者看下節遍歷整個 map 容器1 std ::cout << "name: " << studentMap[1 ] << "\n" ;
map 容器的迴圈遍歷 迴圈遍歷 map 容器的方式有幾種,以下先介紹使用 range-based for loop 來遍歷 map 容器, 這邊故意將 id 不按順序初始化或者插入,先初始化 1
、3
、2
key 鍵值的元素, 之後再插入 5
和 4
key 鍵值的元素,然後我們再來觀察看看是不是 map 會將其排序,std-map2.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> #include <string> #include <map> int main () { std ::map <int , std ::string > studentMap = { {1 , "Tom" }, {3 , "John" }, {2 , "Jack" } }; studentMap[5 ] = "Tiffany" ; studentMap[4 ] = "Ann" ; for (const auto & s : studentMap) { std ::cout << "id: " << s.first << ", name: " << s.second << "\n" ; } return 0 ; }
輸出內容如下,從這個輸出結果發現是 key 鍵值由小到大排列,所以 map 容器裡面真的是會幫你排序的, 在插入元素的同時會根據鍵值來進行排序,1 2 3 4 5 id: 1, name: Tom id: 2, name: Jack id: 3, name: John id: 4, name: Ann id: 5, name: Tiffany
使用前向迭代器,輸出結果跟上列相同,1 2 3 4 5 for (std ::map <int , std ::string >::iterator it = studentMap.begin(); it != studentMap.end(); it++) { std ::cout << "id: " << (*it).first << ", name: " << (*it).second << "\n" ; }
使用反向迭代器的例子,如果嫌 iterator 迭代器名稱太長的話可以善用 auto
關鍵字讓編譯器去推導該變數類型,1 2 3 4 5 for (auto it = studentMap.rbegin(); it != studentMap.rend(); it++) { std ::cout << "id: " << (*it).first << ", name: " << (*it).second << "\n" ; }
反向迭代器的輸出結果如下,反著印出來,1 2 3 4 5 id: 5, name: Tiffany id: 4, name: Ann id: 3, name: John id: 2, name: Jack id: 1, name: Tom
使用 string 當 key 鍵值, int 當 value 資料的 map 範例 這個範例跟之前的範例相反,我們試著用 string 當作 key 鍵值,int 當 value,看看是不是也可以這樣使用, 所以會寫成 std::map<std::string, int>
這樣,完整範例如下,
std-map3.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <iostream> #include <string> #include <map> int main () { std ::map <std ::string , int > map = { {"Tom" , 1 }, {"Jack" , 2 }, {"Ann" , 4 } }; for (const auto & n : map ) { std ::cout << "key: " << n.first << " value: " << n.second << "\n" ; } map ["Tiffany" ] = 5 ; map ["John" ] = 3 ; std ::cout << map ["John" ] << "\n" ; std ::cout << map ["Tiffany" ] << "\n" ; for (const auto & n : map ) { std ::cout << "key: " << n.first << " value: " << n.second << "\n" ; } return 0 ; }
輸出內容如下,可以發現印出來的順序是按照學生姓名的順序,1 2 3 4 5 6 7 8 9 10 key: Ann value: 4 key: Jack value: 2 key: Tom value: 1 3 5 key: Ann value: 4 key: Jack value: 2 key: John value: 3 key: Tiffany value: 5 key: Tom value: 1
使用 string 當 key 鍵值, 自定義類別或自定義結構當 value 資料的 map 範例 如果要在 value 欄位放入自定義 struct 或 自定義 class 的話,可以參考下面這個範例, 那個宣告就會是 std::map<std::string, Class/Struct>
這樣子寫,
std-map4.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <string> #include <map> struct Student { int id; std ::string name; int age; }; int main () { std ::map <std ::string , Student> studentMap; studentMap["Tom" ] = {1 , "Tom" , 18 }; studentMap["Ann" ] = {4 , "Ann" , 20 }; studentMap["Jack" ] = {2 , "Jack" , 16 }; for (const auto & m : studentMap) { std ::cout << "name: " << m.first << " id: " << m.second.id << " age: " << m.second.age << "\n" ; } return 0 ; }
輸出內容如下:1 2 3 name: Ann id: 4 age: 20 name: Jack id: 2 age: 16 name: Tom id: 1 age: 18
刪除 map 指定的元素 刪除 map 指定的元素要使用 erase()
,std-map5.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <string> #include <map> int main () { std ::map <int , std ::string > studentMap; studentMap[1 ] = "Tom" ; studentMap[7 ] = "Jack" ; studentMap[15 ] = "John" ; studentMap.erase(1 ); for (const auto & m : studentMap) { std ::cout << m.first << " " << m.second << "\n" ; } return 0 ; }
結果如下,
那如果 map 刪除不存在的元素會發生什麼事呢?std-map6.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <string> #include <map> int main () { std ::map <int , std ::string > studentMap; studentMap[1 ] = "Tom" ; studentMap[7 ] = "Jack" ; studentMap[15 ] = "John" ; auto ret = studentMap.erase(1 ); std ::cout << ret << "\n" ; for (const auto & m : studentMap) { std ::cout << m.first << " " << m.second << "\n" ; } ret = studentMap.erase(2 ); std ::cout << ret << "\n" ; for (const auto & m : studentMap) { std ::cout << m.first << " " << m.second << "\n" ; } return 0 ; }
map 刪除不存在的元素並不會造成什麼 crash 這種嚴重問題,他反而會回傳一個數量告訴你它刪除了多少個元素,以這個例子來說 erase(1)
是刪除了 1 個元素,erase(2)
是刪除了 0 個元素,結果如下,1 2 3 4 5 6 1 7 Jack 15 John 0 7 Jack 15 John
map erase()
刪除元素還有另外兩種用法,有興趣的可以看這一篇 。
清空 map 容器 要清空 map 容器的的話,要使用 clear()
,1 2 3 4 5 6 std ::map <int , std ::string > studentMap;studentMap.insert(std ::pair<int , std ::string >(1 , "Tom" )); studentMap.insert(std ::pair<int , std ::string >(7 , "Jack" )); studentMap.insert(std ::pair<int , std ::string >(15 , "John" )); studentMap.clear();
判斷 map 容器是否為空 要判斷 map 是否為空或是裡面有沒有元素的話,可以用 empty()
,寫法如下,1 2 3 4 5 6 7 8 std ::map <int , std ::string > studentMap;studentMap.clear(); if (studentMap.empty()) { std ::cout << "empty\n" ; } else { std ::cout << "not empty, size is " << studentMap.size() <<"\n" ; }
參考 std::map - cppreference.comhttps://en.cppreference.com/w/cpp/container/map map - C++ Referencehttp://www.cplusplus.com/reference/map/map/ Map in C++ Standard Template Library (STL) - GeeksforGeekshttps://www.geeksforgeeks.org/map-associative-containers-the-c-standard-template-library-stl// C/C++ - Map (STL) 用法與心得完全攻略 | Mr. Opengatehttps://mropengate.blogspot.com/2015/12/cc-map-stl.html [教學]C++ Map(STL)詳細用法 @ 一個小小工程師的心情抒發天地http://dangerlover9403.pixnet.net/blog/post/216833943 C++ STL map 的小筆記 @ 伊卡洛斯之翼http://kamory0931.pixnet.net/blog/post/119251820 C++中的STL中map用法详解 - Boblim - 博客园https://www.cnblogs.com/fnlingnzb-learner/p/5833051.html 程式扎記: [C++ 範例代碼] 使用 STL 的 map 操作範例http://puremonkey2010.blogspot.com/2010/08/c-stl-map.html
其它相關文章推薦 如果你想學習 C++ 相關技術,可以參考看看下面的文章,C/C++ 新手入門教學懶人包 std::multimap 用法與範例 std::unordered_map 用法與範例 std::vector 用法與範例 std::deque 介紹與用法 std::queue 用法與範例