3. 树形结构的关联式容器——map
map使用文档
- map是关联式容器它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素
- 在map中key是排序和唯一标识的元素,value中存放的是与key相关的内容,key和value的类型不需要相同;在map中存放的类型不是key也不是value,而是一个pair对象,pair对象中的内容是key和value,在实现上是一个typedef,typedef pair<const key,value> value_type.
- 在map内部的元素存放位置严格按照key的强弱顺序排列,强弱顺序的比较规则又仿函数Compare控制,默认的仿函数是less
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)
- map支持下表访问符[],即通过key访问到value
- map的底层是一个平衡搜索树(红黑树)
1. 默认成员函数
默认成员函数和set的用法非常相似,这里就不过多介绍了
2. 迭代器
迭代器的使用方式也是极其相似的,也就不多介绍了,有需要的朋友直接看文档即可
3. 容量与数据访问
函数原型 | 解释 |
bool empty() const | 判断map是否为空,如果为空,返回true,否则返回false |
size_type size() const | 返回map中的元素个数,数据类型是size_type(unsigned int) |
mapped_type& operator[] (const key_type& k); | 返回key对应的value,这个value可以被修改 |
在map中有一个独特的数据访问方式:map中重载了operator[]操作符,可以通过key作为类似下标的方式访问到对应的value
对于这个特性,这里还有一种很新奇的的用法
/统计单词出现次数 vector<string> vs = {"apple", "banana", "apple","orange", "watermelon", "orange", "apple", "watermelon", "watermelon", "apple", "orange", "apple"}; map<string,int> m1; for(const auto& e : vs) { m1[e]++; }
🙋当key不在map中时,通过operator获取对应value时会发生什么问题?
通过查看文档可知,如果使用的key不在map里面的时候,会自动调用insert函数插入一个key,然后使用value的默认构造创建一个值,构造一个pair对象,然后插入到map中。与其不同的是,at接口遇到这种情况的时候就会抛出异常。
这个原因也就是上面的新奇用法的原理。
void Test6() { vector<string> vs = {"apple", "banana", "apple","orange", "watermelon", "orange", "apple", "watermelon", "watermelon", "apple", "orange", "apple"}; map<string,int> m1;//默认构造 for(const auto& e : vs)//统计次数的方式 { m1[e]++; } map<string,int> m2(m1.begin(), m1.end());//迭代器区间 map<string,int> m3(m1);//拷贝构造 m1 = m3;//赋值重载 cout << "---------------m1---------------" << endl; for(const auto& e : m1) { cout << e.first << ":" << e.second << endl; } cout << "---------------m2---------------" << endl; for(const auto& e : m2) { cout << e.first << ":" << e.second << endl; } cout << "---------------m3---------------" << endl; for(const auto& e : m3) { cout << e.first << ":" << e.second << endl; } }
4.数据修改
数据的修改部分,只看接口的话,发现和set基本一致,用法之类的也都是一致的,没有什么特殊情况,所以也就不多说了。直接上示例:
void Test7() { map<string, string> dict; dict.insert(make_pair("left", "左边")); dict.insert(make_pair("right", "右边")); dict.insert(make_pair("string", "字符串")); dict.insert(make_pair("sort", "排序")); for(const auto& e : dict) { cout << e.first << ":" << e.second << endl; } cout << "------after erase------" << endl; dict.erase("insert"); for(const auto& e : dict) { cout << e.first << ":" << e.second << endl; } cout << "------after swap------" << endl; map<string, string> dict_swap; dict_swap.insert(make_pair("swap", "交换")); dict.swap(dict_swap); cout << "dict:" << endl; for(const auto& e : dict) { cout << e.first << ":" << e.second << endl; } cout << "dict_swap:" << endl; for(const auto& e : dict_swap) { cout << e.first << ":" << e.second << endl; } cout << "------after clear------" << endl; dict.clear(); for(const auto& e : dict) { cout << e.first << ":" << e.second << endl; } }
5. 其他操作接口
这里的操作接口与set的接口完全一样,就不过多赘述了。
<map>头文件中还包含了multimap这个容器,同样的multimap和map的用法完全基本相同,唯一的区别就是multimap允许重复的key值存在。和set与miltiset的关系一样,有需要的可以去对照上文的set和multiset。
本节完。。。