学习笔记:浅谈 STL

浅谈 STL

(从 basic_algorithm贺的,只是为了复习而已)

为什么 C++ 比 C 更受人欢迎呢?除了 C++ 的编译令人感到更舒适,C++ 的标准模板库(STL)也占了很重要的原因。当你还在用手手写快排、手写二叉堆,挑了半天挑不出毛病的时候,C++ 党一手 STL 轻松 AC,想不嫉妒都难。所以在学习 STL 的时候应认真体会 STL 语法及功能,提升自己在算法竞赛及程序设计中解题、码代码的能力。

1 vector

1.1 简介

vector 一词在英文中是向量的意思。

vector 为可变长数组(即动态数组),可以随时添加数值和删除数值。

注意

在局部区域中开 vector 是在堆空间开的

在局部区域开数组是在栈空间开的,而栈空间比较小,如果开了很大的数组就会爆栈。

所以,在局部区域中不能开大数组,但能开大 vector

1.2 头文件

#include <vector>

1.3 初始化

vector<int> a; //定义了一个名为a的一维数组,数组存储int类型数据
vector<double> b;//定义了一个名为b的一维数组,数组存储double类型数据
vector<node> c;//定义了一个名为c的一维数组,数组存储结构体类型数据,node是结构体类型
vector<int> v(n);//定义一个长度为n的数组,初始值默认为0,下标范围[0, n - 1]
vector<int> v(n, 1);//v[0]到v[n-1]所有的元素初始值均为1
//注意:指定数组长度之后(指定长度后的数组就相当于正常的数组了)
vector<int> a{1, 2, 3, 4, 5};//数组a中有五个元素,数组长度就为5
vector<int> a(n + 1, 0);
vector<int> b(a);//两个数组中的类型必须相同,a和b都是长度为n+1,初始值都为0的数组
vector<int> v[5];//定义可变长二维数组
//注意:行不可变(只有5行), 而列可变,可以在指定行添加元素
//第一维固定长度为5,第二维长度可以改变
vector<vector<int> > v;//定义一个行和列均可变的二维数组

1.4 函数

函数 含义
front() 返回第一个数据 $O(1)$
pop_back() 删除最后一个数据 $O(1)$
push_back(x) 在尾部加一个数据 $O(1)$
size() 返回数据个数 $O(1)$
clear() 清空容器 $O(n)$
resize(x, y) 将数组大小改为 x, x 个空间赋值为 y,没有 y 默认为 0
insert(x, y) 向迭代器 x 中插入一个数据 y $O(n)$
erase(x, y) 删除 $[x, y)$ 中的所有数据 $O(n)$
begin() 返回首元素迭代器 $O(1)$
end() 返回末元素后一个位置的迭代器 $O(1)$
empty() 判断容器是否为空 $O(1)$

1.5 访问

可以直接和数组一样访问。

vector<int> a;
a.push_back(1);
cout << a[0] << endl;

也可以采用迭代器访问。

vector <int> a;
a.push_back(1);
vector <int>::iterator tmp = a.begin();
cout << *tmp << endl;
for(tmp = a.begin() ; tmp != a.end() ; tmp ++)
        cout << *tmp << endl;

也可以使用智能指针,但只能一次性遍历完整个数组。

vector<int> v;
v.push_back(12);
v.push_back(241);
for(auto val : v) 
    cout << val << " "; // 12 241

2 stack

2.1 简介

栈是一种先进后出的容器。

2.2 头文件

#include <stack>

2.3 初始化

stack<int> s;
stack<string> s;
stack<node> s; //node是结构体类型

2.4 函数

函数 含义
push(x) 将 x 入栈 $O(1)$
pop() 将栈顶元素出栈 $O(1)$
top() 返回栈顶元素 $O(1)$
empty() 检测栈是否为空 $O(1)$
size() 返回元素个数 $O(1)$

2.5 访问

STL 中的栈仅支持读取栈顶元素,如果需要遍历则需要将所有元素出栈。

可以考虑用数组模拟栈,比 STL 的 stack 容器速度更快,且遍历元素更加方便。

3 queue

3.1 简介

队列是一种先进先出的数据结构。

3.2 头文件

#include <queue>

3.3 初始化

queue<int> s;
queue<string> s;
queue<node> s; //node是结构体类型

3.4 函数

函数 含义
front() 返回队首元素 $O(1)$
back() 返回队尾元素 $O(1)$
push(x) 在尾部加入一个元素 $O(1)$
pop() 将第一个元素出队 $O(1)$
size() 返回队列元素个数 $O(1)$
empty() 判断是否为空 $O(1)$

3.5 访问

STL 中的队列仅支持访问队首和队尾的元素,如果要遍历队列中的元素则需要将所有元素出队。

可以考虑用数组模拟队列。

4 deque

4.1 简介

首尾都可以插入和删除元素的队列为双端队列。

4.2 头文件

#include <deque>

4.3 初始化

deque<int> s;
deque<string> s;
deque<node> s; //node是结构体类型

4.4 函数

函数 含义
front() 返回队首元素 $O(1)$
back() 返回队尾元素 $O(1)$
push_front(x) 加入一个元素到队首 $O(1)$
push_back(x) 加入一个元素到队尾 $O(1)$
pop_front() 将第一个元素出队 $O(1)$
pop_back() 将最后一个元素出队 $O(1)$
size() 返回队列元素个数 $O(1)$
empty() 判断是否为空 $O(1)$
clear() 清空 deque

注意

deque 可以进行排序。

5 priority_queue

5.1 简介

优先队列在正常队列的基础上加入了优先级,保证每一次插入元素后队首元素都是优先级最大的。其底层实现是堆。

5.2 头文件

#include <queue>

5.3 初始化

priority_queue<int> s;
priority_queue<string> s;
priority_queue<node> s; //node是结构体类型

5.4 函数

函数 含义
top() 返回队首元素
push(x) 将元素入队
pop() 队首元素出队
size() 返回元素个数
empty() 判断是否为空

5.5 设置优先级

优先队列默认实现的是大根堆,如果需要实现小根堆的话可以考虑在入队和出队时对元素进行取反。

也可以设置参数。

priority_queue<int> q1; // 默认大根堆, 即每次取出的元素是队列中的最大值
priority_queue<int, vector<int>, less<int> > q2; // 大根堆, 每次取出的元素是队列中的最大值,同第一行

priority_queue<int, vector<int>, greater<int> > q3; // 小根堆, 每次取出的元素是队列中的最小值

第二个参数: vector<int> 是用来承载底层数据结构堆的容器,若优先队列中存放的是 double 型数据,就要填 vector<double> 总之存的是什么类型的数据,就相应的填写对应类型。同时也要改动第三个参数里面的对应类型。

第三个参数: less<int> 表示数字大的优先级大,堆顶为最大的数字 greater<int> 表示数字小的优先级大,堆顶为最小的数字 int代表的是数据类型,也要填优先队列中存储的数据类型

也可以重载运算符。

struct node
{
    int x;
    bool operator<(const int &x)
    {
        return x > x.x;
    }
};
priority_queue <node> q;

如果需要使用结构体类型也需要进行进行小于号重载。

特殊类型的优先级

排序规则: 默认先对 pairfirst 进行降序排序,然后再对 second 降序排序 对 first 先排序,大的排在前面,如果 first 元素相同,再对 second 元素排序,保持大的在前面。

6 map/multimap

6.1 简介

STL 中的 map 并不是真正的地图,而是一种类似于函数的对应关系。内部实现为红黑树。

浅浅地举个栗子:

设函数 $f(x)=x+1(x\in \R)$,则对于任意一个 $x$ 都有一值 $x+1$ 与其对应。

map 中就变成了每一个键对应一个值。

6.2 头文件

#include <map>

6.3 初始化

map<int, int> mp;

6.4 函数

函数 含义
find(x) 返回键为 x 的映射的迭代器 $O(\log n)$,数据不存在时返回末尾迭代器
erase(x) 删除迭代器对应的键值 $O(1)$,或者根据键删除键值 $O(logn)$
size() 返回映射的对数 $O(1)$
clear() 删除所有映射 $O(n)$
insert(x) 插入键值 x $O(\log n)$
empty() 判断是否为空 $O(1)$
begin() 返回第一个元素迭代器 $O(1)$
end() 返回最后一个元素的后一个迭代器 $O(1)$
lower_bound(x) 返回指向键值 $\geq$ x 的第一个元素 $O(\log n)$
upper_bound(x) 返回指向键值 $>$ x 的第一个元素 $O(\log n)$
rbegin() 返回指向 map 最后一个元素迭代器 $O(1)$
rend() 返回指向 map 第一个原色前面的逆向迭代器 $O(1)$
count(x) 检查元素 x 是否存在 $O(\log n)$

6.5 添加

mp["yb"] = "akioi";
mp["yzj"] = "wc2023au";
mp.insert(make_pair("hhy","chickenbrother"));
mp.insert(pair<string, string>("yxf","大师"));
mp.insert({"tsq","tsqtsqtsq"});

6.6 访问

map 可以使用下标访问,也可以使用迭代器访问。

mp["yzj"] = "wc2023au";
cout << mp["yzj"] << endl;

map<char,int>::iterator it = mp.find(`a`);
cout << it -> first << " " <<  it -> second << endl;

智能指针:

for(auto i : mp)
    cout << i.first << " " << i.second << endl;//键,值

正向遍历:

map<int, int> mp;
mp[1] = 2;
mp[2] = 3;
mp[3] = 4;
auto it = mp.begin();
while(it != mp.end())
{
    cout << it -> first << " " << it -> second << endl;
    it++;
}

逆向遍历:

map<int,int> mp;
mp[1] = 2;
mp[2] = 3;
mp[3] = 4;
auto it = mp.rbegin();
while(it != mp.rend())
{
    cout << it -> first << " " << it -> second << endl;
    it++;
}

注意:map 中键不能重复,但 multimap 可以。

7 set/multiset

7.1 简介

"set"一词的中文意思为“集合”,set 容器具有数学中集合的所有特性(除 multiset 允许存在重复元素之外),当插入元素时会自动从小到大排序。其内部实现为红黑树。

7.2 头文件

#include <set>

7.3 初始化

set<int> s;
set<string> s;
set<node> s; //node是结构体类型

7.4 函数

函数 含义
begin() 返回第一个元素迭代器 $O(1)$
end() 返回最后一个元素下一个地址的迭代器 $O(1)$
clear() 删除所有元素 $O(n)$
empty() 判断容器是否为空 $O(1)$
insert() 插入一个元素 $O(\log n)$
size() 返回元素个数 $O(1)$
lower_bound(x) 返回值 $\geq$ x 的第一个元素 $O(\log n)$
upper_bound(x) 返回值 $>$ x 的第一个元素 $O(\log n)$
find(x) 返回 x 元素的迭代器 $O(\log n)$,数据不存在时返回末尾迭代器
rbegin() 返回指向 map 最后一个元素迭代器 $O(1)$
rend() 返回指向 map 第一个原色前面的逆向迭代器 $O(1)$
count(x) 检查元素 x 是否存在 $O(\log n)$

7.5 访问

可以使用迭代器访问。

for(set<int>::iterator it = s.begin(); it != s.end(); it++)
    cout << *it << " ";

智能指针

for(auto i : s)
    cout << i << endl;

访问最后一个元素

//第一种
cout << *s.rbegin() << endl;

//第二种
set<int>::iterator iter = s.end();
iter--;
cout << (*iter) << endl; //打印2;

//第三种
cout << *(--s.end()) << endl;

7.6 重载运算符

set<int> s1; // 默认从小到大排序
set<int, greater<int> > s2; // 从大到小排序

//重载 < 运算符
struct cmp
{
    bool operator()(const int& u, const int& v)const
    {
       // return + 返回条件
       return u > v;
    }
};
set<int, cmp> s; 

for(int i = 1; i <= 10; i++)
    s.insert(i);
for(auto i : s)
    cout << i << " ";
// 10 9 8 7 6 5 4 3 2 1

结构体

struct Point
{
    int x, y;
    bool operator<(const Point &p)const
    {
        // 按照点的横坐标从小到大排序,如果横坐标相同,纵坐标从小到大
        if(x == p.x)
            return y < p.y;
        return x < p.x;
    }
};

set<Point> s;
for(int i = 1; i <= 5; i++)
{
    int x, y;
    cin >> x >> y;
    s.insert({x, y});
}    
/* 输入
5 4
5 2
3 7
3 5
4 8
*/

for(auto i : s)
    cout << i.x << " " << i.y << endl;
/* 输出
3 5
3 7
4 8
5 2
5 4
*/

注意:set 中值不能重复,但 multiset 可以。

8 pair

1 简介

pair 容器中只含有两个元素,可以看作是一种只有两个元素的结构体。

应用:

代替二元结构体

作为 map 键值进行插入

2 头文件

#include <utility>

3 初始化

pair<string,int> p("yb",114514);//带初始值的
pair<string,int> p;//不带初始值的

4 访问

//定义结构体数组
pair<int, int> p[20];
p[1] = {"yb",114514};
for(int i = 0; i < 20; i++)
{
    //和结构体类似,first代表第一个元素,second代表第二个元素
    cout << p[i].first << " " << p[i].second;
}

9 string

string 是一个字符串类,和 char 字符串类似。

9.1 头文件

#include <string>

9.2 特性

支持比较运算符

$+$ 代表拼接字符串

$>,<,\geq,\leq$ 代表根据字典序比较字符串的大小

9.3 读入

读入字符串,遇到空格结束。

string s;
cin >> s;

读入字符串(包括空格),遇到回车结束。

string s;
getline(cin, s);

注意:getline 会获取前一个输入的换行符吗,需要在前面添加读取换行符的语句,如 getchar()

9.4 卡常

ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);

注意:在解锁之后不能混用 scanf, printf,getchar,getline

9.5 函数

函数 含义
size() 和 length() 返回字符个数
max_size() 返回最多包含字符数
capacity() 重新分配内存之前最多包含字符数
push_back() 在末尾插入字符
insert(x, y) 在 x 处插入字符 y
append(x) 在字符串结尾处添加字符串 x
erase(x) 删除字符串中 x 所指的字符
erase(x, y) 删除 $[x, y)$ 上的所有字符
erase(x, y) 删除从 x 开始的 y 个字符
replace(x, y, z) 将当前字符串从 x 开始的 y 个字符替换为 z
replace(x, y, z, t) 将当前字符串从 x 开始的 y 个字符替换为 z 个字符 t
tolower(s[i]) 转换为小写
toupper(s[i]) 转换为大写
substr(x, y) 截取从 x 开始的 y 个字符
find(x, y) 从 x 开始寻找 y
rfind(x, y) 从 x 开始反向寻找 y

10 bitset

10.1 简介

bitset 是标准库中的一个存储 0/1 的大小不可变容器,它类似数组,并且每一个元素只能是0或1,每个元素只用1bit空间。

10.2 头文件

#include <bitset>

10.3 初始化

方法 含义
bitset < n > a a 有 n 位,每一位都为 0
bitset < n >a(b) a 是 unsigned long 型 u 的一个副本
bitset < n >a(s) a 是 string 对象 s 中含有的位串的副本
bitset < n >a(s, pos, n) a 是 s 中从位置 pos 开始的 n 个位的副本

10.4 特性

可以进行位操作

bitset<4> foo (string("1001"));
bitset<4> bar (string("0011"));
cout << (foo ^= bar) << endl;// 1010 (foo对bar按位异或后赋值给foo)
cout << (foo &= bar) << endl;// 0010 (按位与后赋值给foo)
cout << (foo |= bar) << endl;// 0011 (按位或后赋值给foo)
cout << (foo <<= 2) << endl;// 1100 (左移2位,低位补0,有自身赋值)
cout << (foo >>= 1) << endl;// 0110 (右移1位,高位补0,有自身赋值)
out << (~bar) << endl;// 1100 (按位取反)
cout << (bar << 1) << endl;// 0110 (左移,不赋值)
cout << (bar >> 1) << endl;// 0001 (右移,不赋值)
cout << (foo == bar) << endl;// false (0110==0011为false)
cout << (foo != bar) << endl;// true (0110!=0011为true)
cout << (foo & bar) << endl;// 0010 (按位与,不赋值)
cout << (foo | bar) << endl;// 0111 (按位或,不赋值)
cout << (foo ^ bar) << endl;// 0101 (按位异或,不赋值)

10.5 函数

函数 含义
any() 是否存在值为 1 的二进制位
none() 是否不存在值为 1 的二进制位
count() 值为 1 的个数
size() 二进制位的个数
test(x) 测试 x 处是否为 1
a[x] 返回 x 处的二进制位
set() 将所有值变为 1
set(x) 将 x 处变为 1
reset() 将所有值变为 0
reset(x) 将 x 处变为 0
flip() 将所有值按位取反
flip(x) 将 x 处按位取反

11 tuple

11.1 简介

tuple 模板是 pair 的泛化,可以封装不同类型任意数量的对象。

可以把 tuple 理解为 pair 的扩展,tuple 可以声明二元组,也可以声明三元组。

tuple 可以等价为结构体使用。

11.2 头文件

#include <tuple>

11.3 初始化

tuple<int, int, string> t1;

11.4 操作

// 赋值
t1 = make_tuple(1, 1, "tsq");

// 创建的同时初始化
tuple<int, int, int, int> t2(1, 2, 3, 4);

// 可以使用pair对象构造tuple对象,但tuple对象必须是两个元素

auto p = make_pair("yb", 114514);
tuple<string, int> t3 {p}; //将pair对象赋给tuple对象

// 获取tuple对象t的第一个元素
int first = get<0>(t);

// 修改tuple对象t的第一个元素
get<0>(t) = 1;

// 获取元素个数
tuple<int, int, int> t(1, 2, 3);
cout << tuple_size<decltype(t)>::value << endl; // 3

// 获取对应元素的值
// 通过get<n>(obj)方法获取,n必须为数字不能是变量

tuple<int, int, int> t(1, 2, 3);
cout << get<0>(t) << endl; // 1
cout << get<1>(t) << endl; // 2
cout << get<2>(t) << endl; // 3

// 通过tie解包 获取元素值
// tie 可以让 tuple 变量中的三个值依次赋到 tie 中的三个变量中
int one, three;
string two; 
tuple<int, string, int> t(1, "tsq", 3);
tie(one, two, three) = t;
cout << one << two << three << endl; // 1tsq3

12 STL 函数

12.1 accumulate()

accumulate(beg, end, init)

作用:$O(n)$ 对一个元素序列求和。

12.2 atoi()

atoi(const char *)

作用:将字符串转换为 int 类型。

12.3 fill()

fill(beg,end,num)

作用:$O(n)$ 对一个序列初始化赋值。

12.4 is_sorted()

is_sorted(beg,end)

作用:判断序列是否有序。

12.5 iota()

iota(beg, end)

作用:对序列递增赋值。

12.6 lower_bound + upper_bound()

//在a数组中查找第一个大于等于x的元素,返回该元素的地址
lower_bound(a + 1, a + n + 1, x);
//在a数组中查找第一个大于x的元素,返回该元素的地址
upper_bound(a + 1, a + n + 1, x);
//如果未找到,返回尾地址的下一个位置的地址

作用:$O(\log n)$ 二分查找。

12.7 max_element + min_element()

//函数都是返回地址,需要加*取值
int maxx = *max_element(a + 1, a + n + 1);
int minn = *min_element(a + 1, a + n + 1);

作用:$O(n)$ 查找最大最小值。

12.8 max() + min()

//找a,b的最大值和最小值
maxx = max(a, b);
minn = min(a, b);

//找a,b,c,d的最大值和最小值
maxx = max({a, b, c, d});
minn = min({a, b, c, d});

作用:$O(1)$ 查找多个元素最大最小值。

12.9 minmax()

pair<int, int> t = minmax(1919810, 114514);
// t.first = 114514, t.second = 1919810

作用:$O(1)$ 返回一个 pair 类型,第一个元素是 min(a, b) , 第二个元素是 max(a, b)

12.10 random_shuffle()

vector<int> b(n);
iota(b.begin(), b.end(), 1);// 序列b递增赋值 1, 2, 3, 4,...
//对a数组随机重排 random_shuffle(a, a + n);
// C++11之后尽量使用shuffle
shuffle(b.begin(), b.end());

作用:$O(n)$ 随机打乱序列

注意:在 C++14 中被弃用,在 C++17 中被废除,C++11 之后应尽量使用 shuffle 来代替。

12.11 reverse()

reverse(beg, end)

作用:$O(n)$ 翻转序列。

12.12 sort()

sort(beg, end);
sort(beg, end, cmp);

作用:$O(n\log n)$ 对序列排序。

12.13 stable_sort()

功能和sort()基本一样。

区别在于stable_sort()能够保证相等元素的相对位置,排序时不会改变相等元素的相对位置。

12.14 unique()

unique(beg, end);

作用:$O(n)$ 消除重复元素,返回消除完重复元素的下一个位置的地址

如:a[] = {1,2,3,3,4};

unique之后a数组为{1,2,3,4,3}前面为无重复元素的数组,后面则是重复元素移到后面,返回a[4]位置的地址(不重复元素的尾后地址)

12.15 __gcd()

__gcd(a, b)

作用:$O(\log n)$ 求 $a$ 和 $b$ 的最大公约数。

12.16 __lg()

__lg(a)
  1. 求一个数二进制下最高位位于第几位(从第0位开始)(或二进制数下有几位)
  2. __lg(x)相当于返回 $\lfloor log_2x\rfloor$
  3. 复杂度 $O(1)$
posted @ 2023-10-09 21:05  tsqtsqtsq  阅读(25)  评论(0)    收藏  举报  来源