目录
[1. 序列式容器和关联式容器](#1. 序列式容器和关联式容器)
[2. Set的使用](#2. Set的使用)
[2.1 概况](#2.1 概况)
[2.2 主要特点](#2.2 主要特点)
[2.3 去重与打印](#2.3 去重与打印)
[2.4 仿函数的使用](#2.4 仿函数的使用)
[2.5 初始化列表初始化](#2.5 初始化列表初始化)
[2.6 删除操作](#2.6 删除操作)
[2.7 查找操作比较](#2.7 查找操作比较)
[2.8 count函数](#2.8 count函数)
[2.9 lower_bound和upper_bound](#2.9 lower_bound和upper_bound)
[编辑3. Multiset](#编辑3. Multiset)
[3.1 查找操作](#3.1 查找操作)
[3.2 删除操作](#3.2 删除操作)
[4. Map的使用](#4. Map的使用)
[4.1 概况](#4.1 概况)
[4.2 Pair结构](#4.2 Pair结构)
[4.3 插入操作](#4.3 插入操作)
[4.4 插入重复值](#4.4 插入重复值)
[编辑4.5 遍历方法](#编辑4.5 遍历方法)
[4.6 key不可变,val可变](#4.6 key不可变,val可变)
[4.7 []运算符重载](#4.7 []运算符重载)
[4.8 insert返回值](#4.8 insert返回值)
[5. Multimap](#5. Multimap)
1. 序列式容器和关联式容器
-
序列式容器:逻辑结构为线性序列,交换数据后,性质依旧不变
-
关联式容器:两个位置联系紧密,交换会破坏存储结构
2. Set的使用
2.1 概况
-
底层结构:红黑树(平衡二叉搜索树)
-
声明 :数据类型 + 仿函数 + 容器(后两个参数可有默认值)

-
迭代器 :双向迭代器,通过中序遍历得到有序数组

-
构造方式:与list类似
-
默认构造
-
迭代器范围构造
-
拷贝构造
-
初始化列表构造

-
2.2 主要特点
-
有容量相关接口,但使用不多

-
支持增(insert)、删(erase)、查(find)操作


-
不支持修改,因为修改可能破坏红黑树性质
2.3 去重与打印
cpp
set<int> se;
se.insert(2);
se.insert(2);
se.insert(5);
for (auto& e : se)
{
cout << e << " ";
}
cout << endl;
特点:
-
Set会自动去重
-
迭代器中序遍历,打印有序数组
2.4 仿函数的使用
cpp
// 使用greater仿函数实现降序
set<int, greater<int>> se;
se.insert(2);
se.insert(2);
se.insert(5);
// 自定义仿函数
template<class T>
struct Greater
{
bool operator()(const T& a, const T& b) const
{
return a > b;
}
};
set<int, Greater<int>> se;
2.5 初始化列表初始化
cpp
set<int> se;
se.insert({ 2,8,3,9,2 });
本质是遍历初始化列表再插入数据,同样会自动去重。
2.6 删除操作
删除最小值:
cpp
set<int> se;
se.insert({ 2,8,3,9,2 });
se.erase(se.begin()); // 中序遍历,begin迭代器指向最小值
删除指定值:
cpp
set<int> se;
se.insert({ 2,8,3,9,2 });
int num = se.erase(3);
int num2 = se.erase(10);
cout << num << endl; // 输出:1
cout << num2 << endl; // 输出:0
-
成功删除返回删除的个数(set为1,为了和map保持一致)
-
失败返回0

2.7 查找操作比较
cpp
set<int> se;
se.insert({ 2,8,3,9,2 });
auto it = find(se.begin(), se.end(), 9); // 库里的find,复杂度O(n)
auto it2 = se.find(9); // set的find接口,复杂度O(log n)
2.8 count函数
cpp
// 返回值的个数(在set中为0或1,为了和multiset对应)
if (se.count(3))
{
cout << "有3" << endl;
}
// 对比find方法
auto sit = se.find(3);
if(sit != se.end())
{
cout << "有3" << endl;
}
2.9 lower_bound和upper_bound
-
lower_bound:找第一个>=指定值的元素
-
upper_bound:找第一个>指定值的元素
cpp
auto low_it = se.lower_bound(60);
auto up_it = se.upper_bound(60);
cout << *low_it << " " << *up_it << endl;
3. Multiset
允许值冗余的set
3.1 查找操作
cpp
multiset<int> mset = { 2,4,4,3,4,6 };
auto it = mset.find(4); // 找到中序遍历的第一个4
while (it != mset.end() && *it == 4)
{
cout << *it;
++it;
}
// 这样,就可以通过遍历,把所有元素找到
3.2 删除操作
cpp
mset.erase(4); // 删除所有值为4的元素
// erase也可以传迭代器,并返回新的迭代器
4. Map的使用
4.1 概况
总体框架与set类似,但是支持[]重载修改val。
4.2 Pair结构
cpp
pair<int, int> p = { 1,1 };
cout << p.first << ":" << p.second;
// 简易实现
template<class T1, class T2>
struct pair
{
pair()
:first(T1())
, second(T2())
{ }
pair(T1& _first, T2& _second)
:first(_first)
,second(_second)
{ }
T1 first;
T2 second;
};
Map有两个元素,使用的就是pair类型。
4.3 插入操作
cpp
pair<string, string> k1("a", "A");
map<string, string> ma = {
k1, // 1. 构造pair有名对象插入k1
pair<string, string>("b", "B"), // 2. 匿名对象
make_pair("c", "C"), // 3. make_pair函数返回pair类型
{"d", "D"} // 4. 初始化列表
};
4.4 插入重复值
cpp
ma.insert({ "a", "B" }); // 依旧是原来的,不会更新
4.5 遍历方法
范围for循环:
cpp
for (auto& e : ma)
{
cout << e.first << ":" << e.second << endl;
}
迭代器遍历:
cpp
auto it = ma.begin();
while(it != ma.end())
{
cout << it->first << ":" << it->second << endl;
it++;
}
// 本质:
while(it != ma.end())
{
cout << it.operator->()->first << ":" << it.operator->()->second << endl;
it++;
}
// 取出pair的指针,再指向first
4.6 key不可变,val可变
cpp
// ma.begin()->first = "a"; // 错误,key不可修改
ma.begin()->second = "a"; // 正确,value可以修改
4.7 []运算符重载
cpp
map<int, int> ma2;
ma2[2]++; // []有三重含义:插入、查找、修改
[]运算符的功能:
-
有key这个值:查找key并修改value
-
没key这个值:查找key并插入(value使用默认值)
可以充当insert的功能。
4.8 insert返回值
cpp
pair<map<string,string>::iterator, int> r1 = ma.insert({ "a","B" });
pair<map<string, string>::iterator, int> r2 = ma.insert({ "e","E" });
cout << r1.second << ":" << r1.first->first << endl; // 失败:0:a
cout << r2.second << ":" << r2.first->first << endl; // 成功:1:e
-
成功:返回pair<迭代器, true>
-
失败:返回pair<已存在的迭代器, false>

注意,这个pair和插入的pair不是同一个。
5. Multimap
与map的主要区别:
-
每次插入一定成功(允许重复key)
-
erase操作:
mmp.erase("a");将删除所有key为"a"的pair -
不支持[]运算符的修改功能