- § STL
- 1. string
- 2. vector
- 3. stack
- 4. queue
- 5. deque
- 6. priority_queue
- 7. set
- 8. map
- 9. C++11后的容器
- unordered_set和unordered_map
- 刷题
- 1.字符串括号匹配
- 2.仓库日志
- 3.编辑
- 4.敲七
- 5.查字典
- 6.溶液模拟器
- 7.上网统计
-
标准模板库,日常简单理解为标准库
-
这三个字母在C++标准文档中没有出现,是人为制造出来的东西。于是STL的概念就没那么清楚、比较模糊,比如string是标准库里的,但不是标准模板库里的。因此string是不是STL里的不好说
-
不用纠结定义,就当奇闻轶事乐趣
-
6大组件
①容器
②迭代器:理解成指针
③适配器:容器进行二次封装得到的
④算法:如sort、lower_bound
⑤仿函数:C++特性,重载了()使得具有函数功能
⑥分配器:理解为C语言的malloc、calloc
- 头文件include
,string s;对应类 对象,如同int a对应类型 名 - 获取字符串长度
s.size(); s.length(); //返回值是 size_type,与int比较时得强转类型 //两个函数没有任何区别
错误想法:将字符串中的某一个字符改成字符串结束标志,希望把字符串给截掉
string s = "123"; s[1] = ' '; cout << s.size();
- 查找
s.find("abc");
//s.find(查找什么, 下标从ind开始往后找而省略时默认为0)
//返回值也是size_type
//没找到返回值string::npos(no position 的缩写)
//没找到的返回值表现为unsigned long long的极大值即long long -1
//判断是否找到
if (s.find(...) == string::npos)
//将string::nops改成-1不太严谨
- 截取
s.substr(ind, 长度) //ind指的是从下标为ind的位置开始截取 s.substr(ind); //从ind开始截取到末尾
- 替换
s.replace(ind, 被替换字符串的长度, 替换成什么); //删除,替换成空字符串即可
- 插入
s.insert(ind, 插入什么);
以上只是常见用法,在算法做题中够用,其它重载的功能可以在cppreference.com中查看
2. vector-
向量,长度不定的动态数组。头文件#include
,类型定义vector<类型> 变量名 -
判空v.empty(),一般不怎么用,一般用下面的
-
返回元素数量v.size()
-
在vector的最后加入元素xv.push_back(x)
-
清空v.clear()
以上只是写算法题时常用的,在指定位置插入元素略过,因为要使用迭代器 -
初始化与遍历
通过下标访问
//初始化10个int元素,默认0 vectorv1(10); //访问下标为3的元素 //访问跟数组访问的方式一样 cout << v1[3] << endl;
//初始化10个9 vectorv2(10, 9);
//二维数组 //下面的两个>分开是因为C++11标准前的编译器会把>>当成右移运算符 vector> v3(5, vector (6, 10)); //初始化5行的一维数组,每个一维数组存放6个元素10
//列表初始化、遍历 C++11特性 vectorv = {1, 2, 3, 4}; //auto自动推导类型 for (auto x : v) { cout << x << endl; }
- vector有限空间+动态扩容
#include#include using namespace std; int main() { vector v; int t = 0; for (int i = 0; i < 100000; i++) { v.push_back(1); if (t != v.capacity()) { t = v.capacity(); cout << t << endl; } } return 0; }
扩容规则取决于环境、编译器
- 时间复杂度
来源:cppreference
- 栈,stack
sta; - 判空sta.empty()
- 元素数量sta.size()
- 入栈sta.push(x)
下面两个操作得保证栈非空
- 出栈sta.pop()
- 访问栈顶元素sta.top()
栈是用什么实现的?stack
- queue
que,跟stack不能说一模一样,只能说是完全一致 - 判空
- 元素数量
- que.push(x),入队尾;que.pop(),队首出
- 访问队首元素que.front();访问队尾que.back()
演示:玩一个花的。只要是类型已知,都可以存,同理也可以存储自定义类型
#include#include using namespace std; int main() { int num[10] = {1, 2, 3, 4, 5}; queue que; que.push(&num[2]); que.push(&num[4]); while (!que.empty()) { int *p = que.front(); que.pop(); cout << *p << endl; } return 0; }
自定义类型
#include#include using namespace std; struct node { int x, y; }; int main() { queue que; que.push((node){4, 6}); //que.push({4, 6}); que.push({0, 9}); que.push({5, -1}); que.push({0, 0}); cout << "元素数量:" << que.size() << endl; while (!que.empty()) { node temp = que.front(); que.pop(); cout << temp.x << " " << temp.y << endl; } return 0; }
- 实现方式和栈一样,是一个容器适配器
-
双端队列,顺序容器,支持随机访问即可以通过[]直接访问
基本操作 -
判空、获得数量
-
插入:队尾que.push_back(x),队首que.push_front(x)
-
删除:队尾que.pop_back(),队首que.pop_front()
-
访问队首队尾元素:que.back(),que.front()
-
问题:以上操作时间复杂度都是常数级别O(1),随机访问不是应该内存连续?双端队列底层实现逻辑:内存不连续,二级指针,通过偏移量访问
- 优先队列,和queue共用一个头文件
- 默认是大顶堆
- 操作和队列一样,除了访问元素。访问堆顶元素:que.top()
- 用小顶堆,用到第二个第三个模板参:priority_queue<类型, 用什么容器存储, 排序方法>,其中“排序方法”默认是less
,与之对应的就是greater 表示小顶堆 - C++中还有一个make_heap函数利用数组建堆,得到优先队列
- 自定义类型
#include7. set#include using namespace std; struct node { int x, y; //跟sort一样必须指定排序方法 //堆里面的重载逻辑反着来 bool operator<(const node &b) const { //<号,大顶堆 return this->x < b.x; } }; //方法二仿函数:重载括号的类 struct cmp { bool operator() (const node &a, const node &b) const { return a.x < b.x; } }; int main() { priority_queue que; //priority_queue , cmp> que; que.push({5, 6}); que.push({10, 1}); que.push({7, 9}); que.push({-1, 2}); que.push({6, 8}); while (!que.empty()) { node temp = que.top(); que.pop(); cout << temp.x << " " << temp.y << endl; } return 0; }
- 集合,有序、去重,默认递增,自定义类型得指定排序规则
- 底层实现:现在能见到的的编译器都用红黑树实现,因为红黑树比较合适。但是标准没有定义,只规定插删等操作是平均对数级别限制复杂度
- 判空、返回集合元素数量
- 插入s.insert(x)
- 删除s.erase(x)
- 查找s.count(x)返回x的数量(要么是0要么是1),s.find(x)返回的是指针/迭代器
代码演示1
#include#include using namespace std; int main() { set s; s.insert(5); s.insert(8); s.insert(2); s.insert(-1); s.insert(0); cout << s.size() << endl; if (s.count(5) == 1) { cout << "5 yes" << endl; } else { cout << "5 no" << endl; } s.erase(5); if (s.count(5) == 0) { cout << "5 no" << endl; } for (auto it = s.begin(); it != s.end(); it++) { cout << (*it) << " "; } cout << endl; return 0; }
结果
代码演示2:自定义类型指定排序方法
#include#include using namespace std; struct node { int x, y; bool operator<(const node &a) const { return x + y > a.x + a.y; } }; int main() { set s; s.insert({5, 0}); s.insert({7, 2}); s.insert({4, 9}); s.insert({11, -1}); cout << s.size() << endl; for (auto it = s.begin(); it != s.end(); it++) { cout << it->x << " " << it->y << "tsum = " << it->x + it->y << endl; //it当成指针使用 } return 0; }
结果
- 映射,唯一关系、键值对存储;有序(根据键排序)去重,map的升级版
- map
m,键值对pair 将两个元素糅在了一起(key→first,value→second),而map中存储的正是这种键值对。键key是唯一的 - 判空、元素数量
- 插入m.insert(pair)
- 删除m.erase(key)删除键即可
- 查找m.count(key)或m.find(key)
- map重载的中括号[],直接用m[key]修改或插入,因此通常都使用中括号插入元素!
代码演示
#include#include
结果
- 用hash实现的集合和映射,简单的用法与set、map完全一样
- 头文件分别为自己的名字
| #include | #include | |
|---|---|---|
| 有序去重 | set | map |
| 有序不去重 | multiset | multimap 中括号访问的是任意的,一般不用 |
| #include | #include | |
|---|---|---|
| 无序去重 | unordered_set | unordered_map |
| #include | #include | |
|---|---|---|
| 无序不去重 | unordered_multiset | unordered_multimap |
- 用自定义类型的unordered_map需要重载hash函数与==运算符
378
样例输入1
a(cc[])bbb()@
样例输出1
YES
样例输入2
a(cc[)]bbb()@
样例输出2
NO
分析:
- 只需要把括号入栈,左括号全入栈,右括号匹配出栈
- 如果不匹配直接输出
- 匹配完若栈不为空说明还有多余的左括号,不匹配
#include2.仓库日志#include #include using namespace std; int main() { stack sta; string s; cin >> s; int f = 0; // 1不匹配 0匹配 for (auto c : s) { if (c == '(' || c == '[' || c == '{') { sta.push(c); } else if (c == ')') { if (!sta.empty() && sta.top() == '(') { sta.pop(); } else { f = 1; break; } } else if (c == ']') { if (!sta.empty() && sta.top() == '[') { sta.pop(); } else { f = 1; break; } } else if (c == '}') { if (!sta.empty() && sta.top() == '{') { sta.pop(); } else { f = 1; break; } } } if (!sta.empty()) f = 1; if (f == 1) cout << "NO" << endl; else cout << "YES" << endl; return 0; }
379
样例输入
13 0 1 0 2 2 0 4 0 2 2 1 2 1 1 2 1 2
样例输出
2 4 4 1 0
分析:建立一个辅助栈,存储最大值,每当存储的货物数量小于等于最大值栈的top元素值,则将此最大值再入一遍;若大于最大值,则入当前值。当然最开始先把0压栈。出栈时一同出栈即可(货物栈可以不需要)。
482
样例输入
dmih 11 B B P x L B B B P y D D P z
样例输出
yxz
分析:光标左右边分别建立栈
384
样例输入
4 3 6
样例输出
3
分析
- 约瑟夫环问题,但这里用数学公式有点麻烦
- 用队列模拟,判断队首,若安全则拿到队尾;否则直接出队
- 当队列元素为1时直接输出
575
样例输入
2 scan 10 word 15 2 scan word
样例输出
10 15
分析
- unordered_map快一些
569
样例输入
100 100 2 P 100 0 Z
样例输出
200 50.00000 100 100.00000
分析
- 溶液质量=溶剂+溶质(盐水=盐+水);浓度=溶质/溶液(盐/盐水)
- 有撤销操作肯定需要栈,存储每步加入的盐水的信息(自定义类型)
- 自定义结构
struct node {
double v, c, salt;//体积、浓度、盐的质量
//salt = v * c / 100; //c的符号是%
};
7.上网统计
566
样例输入
5 7 goodstudyer bookshopa likespacea spaceweb goodstudyer bookshopb likespaceb spaceweb likespacec spaceweb likespacea juiceshop gameplayer gameweb
样例输出
goodstudyer bookshopa bookshopb likespacea spaceweb juiceshop likespaceb spaceweb likespacec spaceweb gameplayer gameweb
分析
- 可以用map,用户 映射 下标
- vector二维数组,每个一维数组存储下标对应的网页地址
- 做法不唯一
其它题目573(用优先队列)



