STL 常用模板
Frather_
2021-02-27 22:18:09
# **$vector$**
## **功能**
动态数组,可实现随时需要随时申请内存。
## **应用方式**
### **创建(定义)**
+ ```vector<类型> a;``` 创建容器
+ ```vector<类型> a(n);``` 创建初始容量为n,元素初始值为0的容器
+ ```vector<类型> a(n, i);``` 创建初始容量为n,元素初始值为i的容器
### **容量**
+ ```.size()``` 返回数组大小
+ ```.empty()``` 若数组为空则返回 $true$ ,否则返回 $false$
### **修改**
+ ```.push_back()``` 向数组尾部添加元素
+ ```.pop_back()``` 删除数组末尾元素
+ ```.insert()``` 向数组中任意部位插入元素
+ ```.erase()``` 删除数组任意位置元素
+ ```.swap( , )``` 交换数组任意位置的元素
+ ```.clear()``` 清空数组
### **访问**
+ ```.begin()``` 头部指针
+ ```.end()``` 尾部指针
+ ```vec[a]``` 可用下标直接访问
+ ```.front()``` 访问第一个元素
+ ```.back()``` 访问最后一个元素
## **示例 $CODE$**
```cpp
#include <vector>
using namespace std;
vector<int> v; //声明部分
int main()
{
v.push_back(9);
v.push_back(7);
v.push_back(4);
v.push_back(3);
v.push_back(2);
v.push_back(1);
v.push_back(3); //插入元素
if (!v.empty()) //判断是否为空
{
v.pop_back(); //3 出
v.pop_back(); //1 出
v.pop_back(); //2 出
}
//迭代器的用法
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); it++) //遍历元素
printf("%d\n", *it);
v.insert(it, 4, 0); //vector 后面会输出 4个0
//插入的位置取决于指针的位置
for (it = v.begin(); it != v.end(); it++) //遍历元素
printf("%d\n", *it);
}
```
# **$set$ 和 $multiset$**
## **功能**
> $set$ 是 $C++ \ \ STL$ 中提供的容器, $set$ 是数学上的集合——具有唯一性,即每个元素只出现一次,而 $multiset$ 则是可重集,两者的内部实现是一棵**红黑树**,它们支持的函数基本相同。 $set$ 用于判断一个集合内元素的有无。(洛谷日报#7)
简单来说,
$set$ 就相当于数学中的集合,
$multiset$ 则相当于可重集合,并且可以自动从小到大排序。
## **应用方式**
### **创建(定义)**
```set<类型> 名称;``` 创建容器
+ ```set<int>s;```
+ ```set<vector<int> >s;``` vector中提供重载
+ ```set<set<int> >s;``` 类似于平衡树嵌套
+ ```multiset<double>s;```
+ ```cpp
struct node
{
......;
};
set<node> s;
bool operator<(const node &a, const node &b)
{
return a.x > b.x;
}
```
雷同于其他数据类型,为一个结构体的 $set$ 排序,需要重载运算符
### **容量**
+ [迭代器](#jump)
+ ```.size()``` 返回集合大小(元素数量)
+ ```.empty()``` 集合为空则返回 $true$ ,否则返回 $false$
+ ```.count(x)``` 返回集合中值为 $x$ 的元素个数,时间复杂度为 $O ( \log n )$
### **修改**
+ ```.clear()``` 清空集合
+ ```.insert()``` 插入元素,返回插入地址的迭代器和是否插入成功的 $bool$ 并成的 $pair$ ,时间复杂度为 $O( \log n)$
+ ```.erase(参数)``` 删除元素(参数可以是元素或者迭代器),返回下一个元素的迭代器,时间复杂度为 $O( \log n)$
+ 在 $multiset$ 中 $s.erase(x)$ 会删除所有值为 $x$ 的元素
### **访问**
+ ```.begin()``` 返回集合的头部元素,即只想集合中最小元素的迭代器,时间复杂度为 $O(1)$
+ ```.end()``` 返回集合的尾部迭代器
+ 由于 $STL$ 中区间都是左闭右开的,则该函数为指向集合中最大元素的下一个位置的迭代器
+ 因此, ```--s.end()``` 才是指向集合中最大元素的迭代器
+ 时间复杂度为 $O(1)$
+ ```.find(x)``` 在集合中查找值为 $x$ 的元素,并返回其迭代器;若不存在,则返回 ```.end()```,时间复杂度为 $O( \log n)$
+ ```.lower_bound(x)``` 表示查找 $\ge x$ 的元素中最小的一个,并返回指向该元素的迭代器,时间复杂度为 $O( \log n)$
+ ```.upper_bound(x)``` 表示查找 $> x$ 的元素中最小的一个,并返回指向该元素的迭代器,时间复杂度为 $O( \log n)$
### <span id="jump">迭代器</span>
+ 双向访问迭代器,不支持随机访问,支持星号解除引用,仅支持 $++$ $--$ 这两个算术操作
+ 若把 $it++$,则 $it$ 将会指向“下一个”元素。这里的下一个是指在 $key$ 从小到大排序的结果中,排在 $it$ 下一名的元素。同理,若把 $it--$ ,则 $it$ 会指向排在上一个的元素
+ ++ -- 操作的复杂度均为 $O( \log n)$
#### **创建**
```set<类型>::iterator it;```
```cpp
set<int>::iterator it = s.begin();
it++;
it--;
```
#### **操作**
+ ```iterator insert(iterator it,x)``` 在迭代器 $it$ 处插入元素 $x$
+ ```iterator erase(iterator it)``` 删除迭代器指针$it$ 处元素
+ ```iterator erase(iterator first,iterator last)``` 删除 $[first, last)$ 之间元素
+ ```iterator begin()``` 返回首元素的迭代器指针
+ ```iterator end()``` 返回尾元素的迭代器指针
+ ```reverse_iterator rbegin()``` 返回尾元素的逆向迭代器指针(即最后一个)
+ ```reverse_iterator rend()``` 返回首元素前一个位置的迭代器指针
#### **遍历 $set$ 及访问其中的元素**
```cpp
//set
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
printf("%d\n",*it); //取出这个迭代器指向的元素
//set嵌套
for (set<set<int>>::iterator it = s.begin(); it != s.end(); it++)
{
//首先取出set中嵌套的set
for (set<int>::iterator rit = (*it).begin(); rit != (*it).end(); rit++)
printf("%d ",*rit); //遍历这个set
printf("\n");
}
```
# **栈 $stack$**
## **功能**
+ 一种先进后出的数据结构,只能操作最顶端的元素。
+ 栈不允许遍历。
![图片来源于网络](https://i.loli.net/2021/02/27/JQWtZ2pqPU5zoOw.png)
## **应用方式**
### **创建(定义)**
```stack<类型> 名称``` 构造创建
### **容量**
+ ```.size();``` 返回栈的大小
+ ```.empty();``` 判断是否为空
### **修改**
+ ```.push()``` 入栈(将元素压入栈顶)
+ ```pop()``` 出栈(将栈顶元素弹出)
### **访问**
+ ```.top()``` 返回栈顶元素
# **队列 $queue$**
## **功能**
+ 一种先进先出的数据结构。它有两个出口
![图片来源于网络](https://i.loli.net/2021/02/27/zC5GaoBl2p3Vu9q.png)
+ 只允许从一端新增元素,从另一端移除元素。
+ 只有队头和队尾允许访问,其余不允许访问。
## **应用方式**
### **创建**
```queue<类型> 名称``` 构造创建
### **容量**
+ ```.size();``` 返回队列的长度
+ ```.empty();``` 判断队列是否为空
### **修改**
+ ```.push()``` 从队尾入队(将元素压入队尾)
+ ```.pop()``` 从队首出队(弹出队首元素)
### **访问**
+ ```.empty();``` 判断队列是否为空
+ ```.size();``` 返回队列的长度
# **双端队列 $deque$**
## **功能**
+ 允许在头部快速插入和删除(就像在尾部一样)的容器。
+ 支持随机访问,即支持 $[]$ 以及 $at()$ ,但是性能没有 $vector$ 好。
+ 可以在内部进行插入和删除操作,但性能不及 $list$ 。
## **应用方式**
### **创建(定义)**
```deque<类型> 名称``` 构造创建
+ ```Constructors``` 创建一个新双向队列
+ ```.assign()``` 设置双向队列的值
### **基本操作**
+ ```Operators``` 比较和赋值双向队列
+ ```.at()``` 返回指定的元素
+ ```.back()``` 返回最后一个元素
+ ```.begin()``` 返回指向第一个元素的迭代器
+ ```.clear()``` 删除所有元素
+ ```.empty()``` 返回真如果双向队列为空
+ ```.end()``` 返回指向尾部的迭代器
+ ```.erase()``` 删除一个元素
+ ```.front()``` 返回第一个元素
+ ```.get_allocator()``` 返回双向队列的配置器
+ ```.insert()``` 插入一个元素到双向队列中
+ ```.max_size()``` 返回双向队列能容纳的最大元素个数
+ ```.pop_back()``` 删除尾部的元素
+ ```.pop_front()``` 删除头部的元素
+ ```.push_back()``` 在尾部加入一个元素
+ ```.push_front()``` 在头部加入一个元素
+ ```.rbegin()``` 返回指向尾部的逆向迭代器
+ ```.rend()``` 返回指向头部的逆向迭代器
+ ```.resize()``` 改变双向队列的大小
+ ```.size()``` 返回双向队列中元素的个数
+ ```.swap()``` 和另一个双向队列交换元素
# **优先队列 $priority \_ queue$**
## **功能**
+ 元素按照一定优先顺序排列的队列。
+ 基础类型默认为大顶堆(即按从大到小的顺序)
## **应用方式**
### **创建(定义)**
```priority_queue<数据类型,容器类型,比较方式> 名称``` 构造创建
+ 容器类型必须为数组实现的容器。
+ ```priority_queue <int,vector<int>,greater<int> > q;``` 升序队列,小顶堆
+ ```priority_queue <int,vector<int>,less<int> >q;``` 降序队列,大顶堆
+ ```greater``` 和 ```less``` 是 $std$ 实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个 ```operator()``` ,这个类就有了类似函数的行为,就是一个仿函数类了)
### **容量**
+ ```.empty()``` 如果优先队列为空,则返回 $true$ ,否则返回 $false$
+ ```.size()``` 返回优先队列中的元素个数
### **修改**
+ ```.pop()``` 删除队首元素(即删除最值)
+ ```.push()``` 加入一个元素,自动排序
### **访问**
+ ```.top()``` 返回优先队列中有最高优先级的元素
## **示例 $CODE$**
```cpp
#include <iostream>
#include <queue>
using namespace std;
int main()
{
priority_queue<int, vector<int>, less<int>> q; //使用priority_queue<int> q1;一样
for (int i = 0; i < 10; i++)
q1.push(i);
while (!q1.empty())
{
printf("%d\n",q1.top());
q1.pop();
}
return 0;
}
```
# **关联容器 映射 $map$ 与 多重映射 $multimap$**
## **功能**
+ $map$ 是一种**关联式**容器,包含“**关键字/值**”。
+ 类似于 $set$ 和 $multiset$,$multimap$ 允许有重复元素,其他与 $map$ 几乎相同
## **应用方式**
### **创建(定义)**
+ ```map<string , int >mapstring;```
+ ```map<int ,string >mapint;```
+ ```map<sring, char>mapstring;```
+ ```map<char ,string>mapchar;```
+ ```map<char ,int>mapchar;```
+ ```map<int ,char >mapint;```
### **基本操作**
+ ```.begin()``` 返回指向 $map$ 头部的迭代器
+ ```.clear()``` 删除所有元素
+ ```.count()``` 返回指定元素出现的次数
+ ```.empty()``` 如果 $map$ 为空则返回 $true$
+ ```.end()``` 返回指向 $map$ 末尾的迭代器
+ ```.equal_range()``` 返回特殊条目的迭代器对
+ ```.erase()``` 删除一个元素
+ ```.find()``` 查找一个元素
+ ```.get_allocator()``` 返回 $map$ 的配置器
+ ```.insert()``` 插入元素
+ ```.key_comp()``` 返回比较元素 $key$ 的函数
+ ```.lower_bound()``` 返回键值 $\ge$ 给定元素的第一个位置
+ ```.upper_bound()``` 返回键值 $>$给定元素的第一个位置
+ ```.max_size()``` 返回可以容纳的最大元素个数
+ ```.rbegin()``` 返回一个指向 $map$ 尾部的逆向迭代器
+ ```.rend()``` 返回一个指向 $map$ 头部的逆向迭代器
+ ```.size()``` 返回 $map$ 中元素的个数
+ ```.swap()``` 交换两个 $map$
+ 不是两个元素交换,是两个 $map$ 容器交换
+ ```.value_comp()``` 返回比较元素 $value$ 的函数
## **示例 $CODE$**
```cpp
/*
代码来自网络。
*/
#include <iostream>
#include <map>
#include <algorithm>
int main(int argc, char *argv[])
{
/* define a map */
std::map _map;
/* insert */
_map.insert(std::map::value_type(0, 32.8));
_map.insert(std::map::value_type(1, 33.2));
_map.insert(std::map::value_type(2, 35.8));
_map.insert(std::map::value_type(3, 36.4));
_map.insert(std::map::value_type(4, 37.8));
_map.insert(std::map::value_type(5, 35.8));
/* 这个是常用的一种map赋值方法 */
_map[7] = 245.3;
/* find by key */
std::map::iterator itr;
itr = _map.find(4);
if (itr != _map.end())
{
std::cout << "Item:" << itr->first << " found, content: " << itr->second << std::endl;
}
std::cout << std::endl;
/* delete item from map */
if (itr != _map.end())
{
_map.erase(itr);
}
/* travel through a map */
std::map::iterator itr1 = _map.begin();
for (; itr1 != _map.end(); ++itr1)
{
std::cout << "Item:" << itr1->first << ", content: " << itr1->second << std::endl;
}
std::cout << std::endl;
/* empty a map */
_map.clear();
return 0;
}
```
# **字符串 $string$**
## **功能**
+ $STL$ 中对于快速方便处理字符串的一类
+ 在定义 $string$ 类对象时,$string$ 类自身可以管理内存
+ 可以使用输入输出流方式直接进行输入输出操作,也可以通过文件等手段进行输入输出操作
## **应用方式**
### **创建(定义)**
```string 名称;``` 直接定义即可
### **基本操作**
+ ==、!=、<、<=、>、>=: 比较字典序
+ ```.size()/length()``` 返回字符串长度,时间复杂度为 $O(1)$
+ ```.insert(pos, string)``` 在 $pos$ 号位置插入字符串 $string$
+ ```.insert(it, it1, it2)``` $it$ 为原字符串的欲插入位置, $it2$ 和 $it3$ 为待插字符串的首尾迭代器,即串 $[it2, it3)$ 插在 $it$ 的位置上
+ ```.erase(it)``` 删除迭代器 $it$ 处的字符
+ ```.erase(first, last)``` 删除迭代器区间 $[first, last)$ 内的元素
+ ```.erase(pos, len)```:从 $pos$ 位开始删除 $len$ 个字符
+ ```.substr(pos, len)``` 返回 $pos$ 位开始、长度 $len$ 的子串,时间复杂度为 $O(len)$
+ ```.find(str2)``` 返回 $str2$ 在 $str$ 第一次出现的位置;如果 $str2$ 不是子串,返回 $string::npos$ 。时间复杂度为 $O(nm)$ ( $n$ 和 $m$ 分别为 $str$ 和 $str2$ 的长度)
+ ```.find(str2, pos)``` 从 $str$ 的 $pos$ 位开始匹配 $str2$ ,返回值同上
+ ```string::npos``` 作为 ```.find()``` 失配时的返回值
+ ```.replace(pos, len, str2)``` 把 $str$ 从 $pos$ 位开始、长度为 $len$ 的子串替换为 $str2$
+ ```.replace(it1, it2, str2)``` 把 $str$ 的迭代器 $[it1, it2)$ 范围的子串替换为 $str2$ 。时间复杂度为 $O(str.length())$
+ ```.clear()``` 清空字符串
# **最后**
奉上作者收藏的[大佬对于**C++标准库和标准模板库**的介绍](https://www.cnblogs.com/jpfss/p/10025771.html)
鸣谢:
+ [洛谷日报#7](https://www.luogu.com.cn/blog/communist/stl-zheng-li-zhi-set)
+ [169IT](https://www.169it.com/)
+ [Cplusplus官网](http://www.cplusplus.com)
+ [淼润淽涵](https://blog.csdn.net/wcxyky/article/details/88082781)
+ [星朝](https://www.cnblogs.com/jpfss/p/10025771.html)
+ [浮生惘语](https://www.cnblogs.com/aerer/p/9931010.html)
+ 等等
如有侵权,请联系删除。