STL 容器笔记
前言
本博客的 stl 按作者自认为的实用度排序。
本博客适用于 C++ 萌新选手。
vector
实用度:
vector 是 C++ 中的一种容器(动态数组)。
它的特点在于定义时,不需要定义数组大小,而且还配有许多函数。
vector 的基本操作如下:
| 函数 | 含义 |
|---|---|
v.push_back(x) |
将 |
v.size() |
|
v.front() |
返回 |
v.back() |
返回 |
v.clear() |
清空 |
v.pop_back() |
删除 |
v.empty() |
返回 |
这里讲些 vector 神操作。
来看这道题目 https://www.luogu.com.cn/problem/P3369。
它会问你排名
C++ 有个函数叫做 lower_bound,可以在有序的数组内找到小于等于
那么每次操作要插入
比如一开始有一个空的 vector
第
第
第
第
我们可以发现,每次插入在小于等于
一行代码:v.insert(lower_bound(v.begin(),v.end(),x),x);
对于删除操作就用 erase:
v.erase(lower_bound(v.begin(),v.end(),x));
其他操作也可以用 vector 库函数实现:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> v;
int n;
cin>>n;
while(n--)
{
int opt,x;
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:v.insert(lower_bound(v.begin(),v.end(),x),x);break;
case 2:v.erase(lower_bound(v.begin(),v.end(),x));break;
case 3:printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);break;
case 4:printf("%d\n",v[x-1]);break;
case 5:printf("%d\n",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);break;
case 6:printf("%d\n",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);break;
}
}
}
然后你发现一道蓝题就被 vector 板子虐了。
当要求有插入,有删除,要有序,可以访问位置
这东西还有个用处,就是可以存图,在
vector<pair<int,int> > g[maxn];
int u,v;
cin>>u>>v;
g[u].push_back(v);
set&multiset
实用度:
set 的基本操作如下:
| 函数 | 含义 |
|---|---|
s.insert(x) |
将 |
s.size() |
|
s.begin() |
返回 |
s.end() |
返回 |
s.empty() |
返回 |
s.lower_bound(x) |
返回 |
s.clear() |
清空 |
set 每次插入值后一直都是保持有序的。可以用迭代器线性遍历 set:
for(set<int>::iterator it=s.begin();it!=s.end();it++)
cout<<*it<<" ";
它还有个兄弟 multiset,区别在于 set 自动去重,multiset 不去重。
它可以实现一个非常牛的东西:珂朵莉树(ODT)。
实现的是随机数据下区间赋值,区间加,单点排名等等,复杂度
至于写法因为篇幅这里就不讲解,详见 This。
set 还可以实现
priority_queue
实用度:
priority_queue 的基本操作如下:
| 函数 | 含义 |
|---|---|
q.push(x) |
将 |
q.size() |
|
q.top() |
|
q.empty() |
返回 |
q.clear() |
清空 |
操作确实不多但巨好用,和 set 一样,每次
在很多地方都很好用,可以快速得出最大或最小的数。
priority_queue 默认大根堆,对于小根堆可以重载运算符或者这样定义:
priority_queue<int,vector<int>,greater<int> >pr;
有时候会出现这种情况,就是我们不光要插入还要删除,很明显优先队列无法直接完成,我们可以用 set,还可以懒标记,要用到下面的 map。
-
对于插入
x ,直接在q 里插进去。 -
对于删除
x ,我们在 mapm 里面标记一下x 删除过一次。 -
对于访问,如果发现堆顶元素在 map 里有记载,那么出队,且在 map 里消除一次删除记录。
priority_queue<int> q;
map<int,int> m;
int op;
cin>>op;
if(op==1)
{
int x;
cin>>x;
q.push(x);
}
if(op==2)
{
int x;
cin>>x;
m[x]++;
}
if(op==3)
{
while(m[q.top()])
m[q.top()]--,q.pop();
cout<<q.top()<<"\n";
}
(直接手搓的,没测试过)。
map&multimap&unordered_map
实用度:
基本操作就 clear(),别的都基本和数组一样。
它的好处是可以用任何值域,任何类型做下标,像 double,像 pair,甚至本身 map,都可以用来存储查询,复杂度为
它也可以用迭代器线性遍历,还会自动去重,用处很广泛。
multimap 和 map 的区别和 set 一样,就是去重没去重。有时候 map 会被卡常,可以用 unordered_map。map 复杂度稳定
bitset
实用度:
(其实本文作者不是很会用这东西)。
deque
实用度:
queue
实用度:
queue 的基本操作如下:
| 函数 | 含义 |
|---|---|
q.push(x) |
将 |
q.size() |
|
q.front() |
返回 |
q.pop() |
|
q.empty() |
返回 |
在 bfs 中很常用,可以实现队列结构。
pair
实用度:
list
实用度:
stack
实用度:
stack 的基本操作如下:
| 函数 | 含义 |
|---|---|
s.push(x) |
将 |
s.size() |
|
s.top() |
返回 |
s.pop() |
删除 |
s.empty() |
返回 |
这个 STL 没有什么特殊用法,但是实现栈结构比较方便。
array
实用度: