C++(标准库):19---STL容器之(关联式容器map、multimap)
2020-04-19 21:19
447 查看
一、关联式容器概述
- STL内部预先定义好的关联式容器有: set:元素依据其value自动排序,每个元素只能出现一次,不允许重复 基础语法参阅:https://blog.csdn.net/qq_41453285/article/details/105483473
- 源码剖析参阅:https://blog.csdn.net/qq_41453285/article/details/104249771
- 对于只有value的关联式容器,例如set、multiset,其对value进行排序。对于key/value pair的关联式容器,例如map、multimap,其根据key进行排序
- 关联式容器底层以平衡二叉树(红黑树)实现,源码剖析参阅:https://blog.csdn.net/qq_41453285/article/details/103645839
二、map
格式
- map<key,value>:由“键值(key)与值(value)”两部分组成,这两者形成映射关系
- 头文件:#include <map>
特点
- key是唯一的,不可重复;但value可以重复出现
- key与value必须具有可赋值、可拷贝的性质
- key的数据类型必须是可比较的,根据key来进行排序(默认为升序)
- key与value可以是任何类型:int、doule、字符串、结构体、类......
- map的每一组key与value相当于一个pair容器对象(pair容器,见文章:https://blog.csdn.net/qq_41453285/article/details/100628402)
key的比较操作
- 我们知道key必须是可以比较的,如果key的类型不能进行比较(例如“<”运算符进行比较),则程序出错
- 如果使我们自定义的类,如果没有提供比较运算符的重载,那么就不能作为关联容器的key使用,因为自定义的类不能进行比较
- 如果key可以进行比较,且遵循下面图片中的规则:
升序、降序操作
- map的key默认为升序排序,但是我们也可以通过一些操作来实现降序操作,或者显式的进行升序操作
- 下面两个标准库函数(less、greater)都在头文件#include <xfunctional>中
- 下面我们先演示默认的升序排序
[code]map<string, int,std::less<string>> word_count;//显式地升序 //map<string, int,> word_count;//默认的升序 string word; while (cin >> word) { ++word_count[word]; } for (const auto &w : word_count) { cout << w.first << " occurs " << w.second << ((w.second>1) ? " times" : " time") << endl; }
- 演示降序排序:
[code]map<string, int,std::greater<string>> word_count;//降序 string word; while (cin >> word) { ++word_count[word]; } for (const auto &w : word_count) { cout << w.first << " occurs " << w.second << ((w.second>1) ? " times" : " time") << endl; }
初始化
- 如果没有给出初始化值,就默认为空容器(使用系统的默认值初始化)
- 手动给出值初始化
下标运算符和at函数
- map和unordered_map提供下标操作,因为其key唯一;multimap与unordered_multimap不提供下标操作,因为其key不唯一
- 下标运算符可以用来创建一个键值对或访问键所对应的值
- 由于下标运算符可能插入一个新元素,我们只可以对非const的map使用下表操作
- 下标运算符则:
- 演示案例:
[code]map<string, size_t> word_count; word_count["a"] = 1; //添加key与value对 word_count["b"] = 2; //添加key与value对 word_count["c"] = 3; //添加key与value对 word_count["a"] = 4; //更改key对应的value cout << word_count["a"] << endl; //打印4 cout << word_count.at("a") << endl; //打印4
迭代器与遍历
- 当解引用一个关联容器迭代器时,我们得到的是容器的value_type的值的引用
- 对于map来说,value_type为一个pair类型,因此得到pair类型之后,我们就可以调用first和second来访问key与value
- 重点:得到的迭代器,我们可以改变其second(value)的值,但不能改变其first(key)的值(因为为const类型)
[code]map<string, int> word_count; word_count["Hello"] = 3; word_count["World"] = 3; auto map_it = word_count.begin(); //得到第一个元素的迭代器 //*map_it是指向一个pair<const string,size_t>的引用 cout << map_it->first << endl;; //打印Hello cout << map_it->second << endl; //打印3 map_it->first = "new key";//错误,key关键字不可以改变(为const类型) ++map_it->second; //正确,key关键字对应的value可以改变
- 通过迭代器遍历容器:可以使用iterator或者const_iterator类型的迭代器遍历
[code]map<string, int> word_count; word_count["Hello"] = 3; word_count["World"] = 3; //map_it为map<string, int>::const_iterator类型 auto map_it = word_count.cbegin(); while (map_it != word_count.cend()) { cout << map_it->first << "" << map_it->second << endl; ++map_it; }
添加元素(insert、emplace)
- 这里介绍的添加元素方式,适合所有关联容器,后面不再介绍
- 对于key唯一的,插入时会先判断key是否存在,不存在则插入;存在则什么都不做
- 对于key不唯一的,每次插入都插入新值
insert有3个版本:
- 参数为value_type或参数为一对迭代器或者参数为一个初始化列表
演示set的插入
[code]vector<int> ivec = { 2,4,6,8,10 }; set<int> set1; set1.insert(ivec.cbegin(), ivec.cend()); //迭代器版本 set1.insert({ 1,3,5,7,9 }); //初始化器版本插入map的插入
- 由于map的key是pair容器类型,因此map的插入有一些特殊情况
[code]map<string, size_t> word_count; word_count.insert({ "a",1 }); word_count.insert(make_pair("a",1)); word_count.insert(pair<string,size_t>("a", 1)); word_count.insert(map<string,size_t>::value_type("a", 1));insert/emplace的返回值
[code]//案例:单词计数 map<string, size_t> word_count; //空的 string word; while (cin >> word) { //插入一个元素,关键字等于word,值为1 //若word已经存在,insert什么都不做 auto ret = word_count.insert({ word,1 }); if (!ret.second) //检查返回值的bool部分,若为false,则word已在word_count中 ++ret.first->second; //递增计数器 }展开递增语句
删除元素(erase)
- 关联容器定义了3个版本的erase: ①传递一个key_type参数。如果元素存在(删除所有匹配给定关键字的元素,返回实际删除的元素数量);如果元素不存在(函数返回0)
- ②传递给erase一个迭代器来删除一个元素,函数返回void(与顺序容器类似)
- ③传递给erase一个迭代器对来删除一个元素范围,函数返回void(与顺序容器类似)
演示案例
[code]map<string, size_t> word_count; word_count["a"] = 1; word_count["b"] = 2; word_count["c"] = 3; string removal_word = "a"; if (word_count.erase(removal_word)) cout << "ok:"<< removal_word <<" removed" <<endl; else cout << "error:" << removal_word << " not found" << endl;
其他操作
- 其他关联容器都可以参数这里的知识点
对map使用find代替下标操作
- 如果使用下标运算符来查找map、unordered_map中的一个关键字,会有一个缺点,就是如果这个关键字不存在,则会插入这个关键字。因此想要寻找一个关键字是否存在map中,最好使用find函数
[code]map<string, size_t> word_count; //空的 //如果不存在,返回map的尾后迭代器 if (word_count.find("abcd") == word_count.end()) cout <<"abcd is not in the map" << endl;在multimap、multiset中查找元素
- multimap、multiset中的key可以重复,并且相同的key会相邻存储,因此如果想要查看相同的key键值,可以使用count和find函数配合查看
[code]multimap<string, string> author; //空的 author.insert({ "C Primer","Bob" }); author.insert({ "C++ Primer","Tom" }); author.insert({ "C++ Primer","Alice" }); author.insert({ "Java","Alan" }); auto entried = author.count("C++ Primer"); //计算出键为“C++ Primer”的数量 auto iter= author.find("C++ Primer");//先找到第一个迭代器位置 while (entried) { //循环遍历 cout << iter->second<< endl; ++iter; --entried; }
lower_bound、upper_bound函数
- 在key可以重复的容器中,lower_bound返回这个key所对应的第一个位置,upper_bound返回最后一个匹配给定关键字的元素的下一个位置
- 如果key不存在,lower_bound和upper_bound返回相等的迭代器——指向一个不影响排序的关键字插入位置
- 根据上面的图片可知,如果key不存在容器中,且大于所有的关键字,则lower_bound返回的就是尾后迭代器
- 这两个函数可以实现上面在multimap、multiset中查找重复的key。见下面案例
[code]multimap<string, string> author; //空的 author.insert({ "C Primer","Bob" }); author.insert({ "C++ Primer","Tom" }); author.insert({ "C++ Primer","Alice" }); author.insert({ "Java","Alan" }); //beg指向于key为"C++ Primer"的第一个位置,end指向于最后一个位置的下一个位置 for (auto beg = author.lower_bound("C++ Primer"), end = author.upper_bound("C++ Primer"); beg != end; ++beg) { cout << beg->second << endl; }
equal_range函数
- 该函数接受一个关键字,然后一个参数为迭代器的pair容器类型
- 若关键字存在,则pair容器中的第一个迭代器指向于第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配元素之后的位置;若不存在关键字,两个迭代器都指向关键字可以插入的位置
- 使用来函数也可以实现上面find、lower_bound等函数来遍历相同的key的操作,见下面演示案例
[code]multimap<string, string> author; //空的 author.insert({ "C Primer","Bob" }); author.insert({ "C++ Primer","Tom" }); author.insert({ "C++ Primer","Alice" }); author.insert({ "Java","Alan" }); for (auto pos = author.equal_range("C++ Primer"); pos.first != pos.second; ++pos.first) { cout <<pos.first->second << endl; } /*pos为pair<iterator1,iterator2>类型, iterator1为指向于第一个"C++ Primer"的迭代器, iterator2指向于最后一个"C++ Primer"的后一个位置*/
演示案例
- 利用map来输入保存的字符串,然后输出字符串出现的次数
[code]#include <iostream> #include <map> #include <string> using namespace std; int main() { //key为string类型,value为size_类型 map<string, size_t> word_count; string word; while (cin >> word) { ++word_count[word]; } for (const auto &w : word_count) { cout <<w.first <<":"<<w.second<<((w.second>1)?"times":"time")<< endl; } return 0; }
三、multimap
格式
- 与map相同:由“键值(key)与值(value)”两部分组成,这两者形成映射关系
- 头文件:#include <map>
特点
- key可以重复(如果有相同的key,则相邻存储),默认也为升序排序
- 其它特点与map相同
- multimap不提供下标操作(下标运算符和at函数),因为key可以重复
升序、降序操作
- 与map相同,key默认是升序操作,我们也可以将key设置为显式地升序或者设置为降序排序
- 下面两个标准库函数(less、greater)都在头文件#include <xfunctional>中
- 演示升序操作
[code]multimap<string, int, std::less<string>> word_count;//升序 //multimap<string, int> word_count;//升序 word_count.insert({ "a",1 }); word_count.insert({ "c",1 }); word_count.insert({ "b",1 }); for (const auto &w : word_count) { cout << w.first << " occurs " << w.second << ((w.second>1) ? " times" : " time") << endl; }
- 演示降序操作
[code]multimap<string, int,std::greater<string>> word_count;//降序 word_count.insert({ "a",1 }); word_count.insert({ "c",1 }); word_count.insert({ "b",1 }); for (const auto &w : word_count) { cout << w.first << " occurs " << w.second << ((w.second>1) ? " times" : " time") << endl; }
初始化
- 如果没有给出初始化值,就默认为空容器
迭代器与遍历
- 与map相似,见map
添加元素(insert、emplace)
- 见map笔记处
删除元素(erase)
- 见map函数,原理相同
其他操作
- 详细介绍,见map容器处
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- C++(标准库):20---STL容器之(无序容器unordered_set、unordered_multiset、unordered_map、unordered_multimap)
- C++之STL(6)之 map 与 multimap 关联容器
- C++中STL容器之映射——map/multimap
- STL关联式容器之map和multimap
- STL之map/multimap关联式容器学习
- STL容器-关联式容器map/multimap
- C++ STL标准库的关联容器set与map
- 【深度探索STL】关联式容器map和multimap
- C++STL学习(5)容器map和multimap
- C++ STL学习之九:关联式容器map深入学习
- C++的STL容器之关联性容器set、multiset、map、multimap
- [C++]STL-map/multimap容器
- c++ 标准库的各种容器(vector,deque,map,set,unordered_map,unordered_set,list)的性能考虑
- c++ 提高4 map容器 共性机制 使用时机 比较| STL算法 算法基础仿函数 谓词 函数适配器 遍历算法
- STL-map和multimap容器
- C++ STL之map和multimap
- STL的基本使用之关联容器:map和multiMap的基本使用
- C++(标准库):22---STL容器之(容器适配器之queue)
- STL概览-关联容器set,multiset,map,multimap(四)
- STL之红黑树容器:set,hash_set,multiset,hash_map,multimap