STL——set map
序列式容器:单纯的存储数据 (vector、list、deque)一级容器
关联式容器:数据之间有关联关系 ( map 、 set等)二级容器
map和set 它们都是 关联容器,内部用 红黑树(有序版本)或 哈希表(unordered 版本)实现
set
set 是 key 搜索模型的容器,提供 增删查 的接口、迭代器(左闭右开) 中序遍历
insert
接收参数:第一个模板参数
pair
返回值,pair,的定义
作为 insert 的返回值:
循环插入一些元素到 set 中:
set<int> s;int arr[] = { 9,8,7,6,5,4,3,2,1,1 };for (int i : arr) // 虽然原生数组没有迭代器,但C++提供了全局的模板函数begin和end{s.insert(i);}for (int i : s) // 范围for打印{cout << i << " ";}cout << endl;
erase
C++11中,对 set 的 erase 的声明中,返回值变成 iterator,形参变为 const iterator
这样的话,我们可以逐个清空 set 元素,而迭代器不会失效
set<int>::iterator it = s.begin();while (it != s.end()){it = s.erase(it); // C++11 后,删除可以返回下一个元素的迭代器,不这么做会导致迭代器失效for (int i : s) // 迭代器打印{cout << i << " ";}cout << endl;}
find
找不到时,对 set::end 解引用触发断言
lower_bound
返回值是一个 【set中 】【>=】 【参数 val】 的 【节点】的 【迭代器】
upper_bound
返回值是一个 【set中 】【>】 【参数 val】 的 【节点】的 【迭代器】
测试:erase的删除区间是 左闭右开,这里的删除区间实际上是 [ 4, 8 )
s.erase(s.lower_bound(4), s.upper_bound(7));
equal_range
接收 equal_range 的返回值,并打印
pair<set<int>::iterator, set<int>::iterator> ret = s.equal_range(6);while (ret.first != ret.second){cout << *(ret.first) << " ";ret.first++; // set 的迭代器是双向迭代器、支持 ++ --}
相当于返回的迭代器区间,也是 左闭右开
multiset
与 set 的主要区别就是,允许 相同元素的存在
那么,set 其实可以对 一组数据进行 去重 + 排序
大部分方法实现与 set 类似,
map
相比 set 的 K模型, map 是 KV 模型的容器,每个元素节点存储 键值对
map 的迭代器也是 双向迭代器
( 单向迭代器:支持 ++
双向迭代器:支持 ++ --
随机迭代器:支持 ++ -- + - )
insert
insert 接受的参数 value_type 也是 pair 类型,只是被 typedef 了👇
即 const pair<const key_type, mapped_type>
(map 的key 值确定后,不能修改)
构造 pair 匿名对象 进行传参
map<string, int> CountMap;CountMap.insert(pair<string, int>("Phone", 1));
Phone 是 const char* 类型,传给 string 采用 string 的带参构造函数 构造一个string 的临时对象传给 pair,再把 int 传给 pair
pair 调用 带参的 构造函数 构造了 pair 这个匿名对象👇,传给了 insert 作为 键值对 插入 Countmap
pair (const first_type& a, const second_type& b);
make_pair
// CountMap.insert(pair<string, int>("Phone", 1));CountMap.insert(make_pair("Phone", 1));
erase
用法类似 set
用法参考 set
operator[ ] 重载
[ ] 运算符的重载,通过 insert 来实现的
给一个 key、返回 value 的引用、、、如果 key 不存在 就添加
分析底层实现:
insert 时,如果不存在就插入、如果存在就返回 该迭代器、相当于 就查找了
insert 返回值 是 一个固定类型的 pair
那么再次访问 pair.first 就是拿到 map 的节点的 迭代器
再次解引用 就是 访问该键值对 的 value,在 [ ] 重载 中, 作为引用返回,外部就可以修改
所以 [ ] 重载 是一个 具有复合功能的 map 的 成员函数
具有:插入、查找、修改、插入+修改
应用:统计每个单词出现的次数:
string strArr[] = { "Phone","Laptop", "TeleVision", "PersonalComputer","Laptop", "TeleVision", "Laptop", "TeleVision" };map<string, int> CountMap;for (string& str : strArr){map<string, int>::iterator ret = CountMap.find(str);if (ret == CountMap.end()) // 没找到该 键值,插入{CountMap.insert(make_pair(str, 1));}else // 找到了,次数++{(*ret).second++;}}for (pair<const string, int>& e : CountMap) // e的类型:pair<const string, int> &//for (auto& e : CountMap) // e的类型:pair<const string, int> &{cout << e.first << ":" << e.second << endl;}
使用 operator[ ] 大幅简化代码:
multimap
大部分方法使用 见 map
multimap 允许键值key 的重复冗余
但也有和 map 的区别,比如:不能支持 operator[ ] 重载,如果有多个重复的 key 不好处理