map的底層實現是紅黑樹,map是有序的,增刪查改一個元素的時間復雜度都是O(log n),使用迭代器遍歷map的時間復雜度是O(n)
map的標准定義如下:
1 template < class Key, // map::key_type 2 class T, // map::mapped_type 3 class Compare = less<Key>, // map::key_compare 4 class Alloc = allocator<pair<const Key,T> > // map::allocator_type 5 > class map;
map中的的鍵和值都可以使用用戶自定義的數據類型,鍵的比較也可以被自定義。
自定義舉例如下,按Mykey中的key值的絕對值從大到小排序,如果key是基本數據類型且不需要特殊排序方式,則不用自定義排序方式。
1 typedef struct Key{ 2 int key; 3 } MyKey; 4 5 typedef struct Value{ 6 string value; 7 } MyValue; 8 9 typedef struct Comp{ 10 bool operator()(const MyKey & k1, const MyKey & k2){ 11 return abs(k1.key) > abs(k2.key); 12 } 13 } MyComp; 14 15 typedef map<MyKey, MyValue, MyComp> MyMap;
聲明一個map常用方法有以下四種,聲明空map,枚舉元素(可以用makepair代替),復制構造函數,利用迭代器實現部分復制
1 map<int, string> a; // 聲明空map 2 map<int, string> b{{1, "aaa"}, {2, "bbb"}}; // 枚舉初始化元素 3 map<int, string> c(b); // 復制構造函數 4 map<int, string> d(begin(b),end(b)); // 通過迭代器實現按區間復制
map中鍵是唯一的,以上聲明方式中的第二種,如果出現重復的key,后出現的不會覆蓋前出現的,而是會以前出現的為准。如下所示
1 map<int, string> e{{1, "aaa"}, {1, "bbb"}}; 2 cout << e.size() << endl; // 1 3 cout << e.find(1)->second; // "aaa"
插入。前三者是等價的,利用前三種方法插入一個鍵值對,如果插入的鍵已存在,編譯器會報錯,而第四種寫法會直接覆蓋原先的鍵值對。
1 a.insert(pair<int, string>(1,"aaa")); 2 a.insert(make_pair<int, string>(2,"bbb")); 3 a.insert(map<int, string>::value_type(3,"ccc")); 4 a[4] = "ddd";
查找。注意,在使用[]運算符返回map中的一個鍵對應的值時,需要先判斷值該鍵值對是否存在。當使用[]時即使查找的鍵不存在編譯器也不會報錯,而是返回垃圾值。
通常可以使用count和find方法判斷一個鍵是否存在,由於map內部時有序的所以不需要遍歷全部鍵值對。count返回個數,find返回找到的元素的位置,如果找不到返回map的末尾位置。以下展示了兩種方法尋找鍵值對,第二種方法更好,因為第一種方法找了兩遍。[]運算符可以使用at成員函數代替。
1 if(a.count(2) > 0) // 方法一 2 return a[2]; 3 4 auto iter1 = a.find(2);// 方法二 5 if(iter != end(a)) 6 return iter->second;
修改。可以使用直接賦值修改或者使用迭代器修改。前者需要先判斷是否存在在修改,后者不需要。另外,map的迭代器支持++運算但是不支持+i運算,只能根據鍵修改值,而不能修改鍵(必須要刪除后重新插入)
1 a[4] = "ddd"; // 方法一 2 3 auto iter2 = ++a.begin(); // 方法二 4 iter2->second = "eee";
刪除,修改一個元素到紅黑樹的時間復雜度O(log N)
1 a.erase(1); // 刪除指定鍵值的元素 2 a.erase(a.begin()); // 刪除迭代器指向的元素 3 a.erase(a.begin(), a.end()); // 刪除迭代器區間內的元素 4 a.clear(); // 清空所有元素
使用迭代器遍歷紅黑樹時間復雜度O(N)
方法一,使用傳統的迭代器遍歷,map的迭代器屬於雙向迭代器,只支持向前加一或者向后減一的操作。
方法二,如果要遍歷整個map而不是某一部分,可以使用C++11中引入的按范圍的for循環。按范圍的for循環中的it迭代器本質上是映射f的右值引用。因此利用it取鍵值要用 . 運算符而不是 ->
1 map<int, string> f{{1,"a"}, {2,"b"}, {3,"c"}}; 2 3 for(auto iter = f.begin(); iter != f.end(); ++iter) 4 cout << iter->first << " : " << iter->second << endl; // 方法一 5 6 for(auto it : f) 7 cout << it.first << " : " << it.second << endl; // 方法二
其他操作
size():返回map的大小
empty():返回一個bool值判斷map是否為空
swap(map1, map2):無返回值,swap是用來交換兩個map的內容而不是用來交換map中的內容。
equal_range(iter1, iter2, val):以pair的形式返回一對迭代器,返回得迭代器的范圍等於iter1和iter2中值等於val的范圍
lower_bound(key):返回map中第一個大於等於key的迭代指針
upper_bound(key):返回map中第一個大於key的迭代指針
emplace(key, val):生成一個pair(key,val),並且把這個pair插入到map中,返回值是一個pair,其中first是一個迭代器,second是一個bool類型。當插入成功,迭代器指向新插入的元素,bool為true,當插入失敗,迭代器指向map中原來已有的key和要插入的key相同的鍵值對,bool位false。
emplace_hint(iter, key, val):作用和emplace相同,不過插入位置由iter指定,而且返回值是迭代器(就是上面的那個first)。對於插入一個元素,使用emplace和emlace_hint效率比insert更高.
key_comp():返回一個用於比較key的比較器
value_comp():返回一個用於比較value的比較器
特殊的迭代器
begin,end,cbegin,cend,rbegin,rend,crbegin,crend