STL学习笔记

写在前面

其实以前是分着写过笔记的,不过感觉那样太麻烦了还不如一起写,所有就有了这篇博客

STL 简介

STL,全称 Standard Template Library,标准模板库,分为“容器”、“迭代器”、“算法”等六部分。 OI中常用的是“容器”及“算法”,这里对这两部分做简要介绍。 OI常用的容器有: vector, queue, stack, deque, priority_queue, set, map 等;除 priority_queue 在 < queue > 中之外它们都在与自己同名的头文件里。

vector

vector是一个常用的变长数组实现。要定义一个 A 类型的 vector,可以 vector < A > v; 它的一些函数如下:
v[i] 访问第 i 个元素(可以修改,i 从 0 开始)(注意,越界时会 RE);
v.front() v.back() 访问第一个元素/最后一个元素;
v.begin() v.end() 返回 v 的首尾迭代器,可以传给 sort / reverse 等函数;
v.size() 返回 v 的长度;
v.empty() 若 v 为空则返回 true,否则返回 false,等价于 (v.size() == 0);
v.clear() 清空内容(并将 size() 重置成 0);
v.push_back(x) 将 x 添加到 v 的末尾(会把 size 变大);
v.pop_back() 将 v 的末尾弹出(会把 size 变小);
v1 < v2, v1 > v2 等比较运算符,比较两个同类型 vector 的字典序。

vector是可以存图的,咕咕咕

#include<iostream>
#include<vector>
using namespace std;
vector<int>q[520];
int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=m; ++i) {
        int x,y;
        cin>>x>>y;
        q[x].push_back(y);
    }
    for(int i=1; i<=n; ++i) {
        for(int j=0; j<q[i].size(); ++j) {
            cout<<q[i][j]<<" ";
        }
        cout<<'\n';
    }
    return 0;
}

queue

queue,即队列,可以用 queue < A > q; 声明。
q.front() q.back() 访问队首/队尾元素;
q.push(x) 将 x 插入队尾;
q.pop() 从队首弹出;
q.empty() 判断队列是否为空;
q.size() 返回队列里元素个数。
注意,queue 没有 clear,对此可以
while (!q.empty()) q.pop();

stack

stack,栈,可以用 stack < A > st; 声明。
st.top() 访问栈顶元素;
st.push(x) 将 x 入栈;
st.pop() 从栈顶弹出;
st.empty() 判断栈是否为空;
st.size() 返回栈中剩余的元素个数。
stack 的清空方式和 queue 相同。

deque

q[i] 返回某个位置的元素(注意,这是 O(1) 的);
q.push_front(x) q.push_back(x) 从首/尾插入;
q.pop_front() q.pop_back() 从首/尾删除;
q.front() q.back() 访问首/尾的元素;
q.empty() q.size() q.clear() 和前面的一样。
deque, queue, stack 的实现比较奇怪,不排除导致 MLE/TLE 的可能,建议考场手写队列(毕竟好写)。

priority_queue

priority_queue < A > q; 定义一个大根堆,A 需要重载小于运算符。
q.top() q.pop() 访问/弹出堆顶;
q.push(x) 插入元素。
如果声明小根堆,可以这样:
priority_queue < A, vector < A > , greater < A > > q;
其中 greater 在 < functional > 里定义

有时候我们想要让 A 是 int,比较方式很奇怪,但是又不想把单个 int 封装到结构体里,这时候可以这样:

struct Cmp {
	bool operator(int a, int b) {
		return /* 返回 true 表示 b 更大,即 b 会先弹出 */;
	}
};
priority_queue	<int, vector<int>, Cmp> q;

set

set 按从小到大顺序维护一个集合。set < A > s; 要求重载小于号。
s.empty() s.size() s.clear() 不用多说。
s.insert(x) 插入一个 x。如果 x 已存在那么什么都不做。
s.erase(x) 删除 x。x 不存在则什么都不做。
s.count(x) 如果 x 存在返回 true,否则返回 false。
s.find(x) 返回指向 x 的迭代器,不存在则返回 s.end()
s.lower_bound(x) 返回最小的大于等于 x 的元素的迭代器,不存在则返回 s.end()。要得到这个元素的值可以 *s.lower_bound(x);
s.upper_bound(x) 类似,返回最小的大于 x 的元素的迭代器。

类似 priority_queue,可以把比较函数封装到结构体里然后 set < A, Cmp > s;

map

map 和 set 类似,但是它维护的每个元素还有一个对应的“值”。map < A, B > m; 要求 A 类型重载了小于号。
m.empty() m.size() m.clear() 跟前面的一样。
m[x] 访问 x 这个元素对应的值。如果不存在会产生一个默认的值存进去(对于int,就会是0)。
m.erase(x) 删除元素 x。x 不存在则什么都不做。
m.count(x) 判断 x 是否存在。
m.find(x) 返回指向 x 的迭代器,不存在则返回 m.end()
m.lower_bound(x) 返回最小的大于等于 x 的元素的迭代器,不存在则返回 s.end()。要得到这个元素或它的值,可以 m.lower_bound(x)- > first 或 m.lower_bound(x)- > second;
m.upper_bound(x) 类似,返回最小的大于 x 的元素的迭代器。

仍然可以 map < A, B, Cmp > 。注意是 A 需要比较,B没有什么要求。

algorithm

algorithm 库封装了许多函数。
copy(A + l, A + r, B) 把 A 数组里 [l, r) 开区间拷贝到 B 数组开头。A+l, A+r 可以换成 vector 的 v.begin(), v.end(), 或者 v.begin()+i。下同
fill(A + l, A + r, v) 把 A 数组里 [l, r) 都赋值为 v。
swap(x, y) 交换两个元素。注意由于大部分 stl 容器只包含一个指针,交换是 O(1) 的。
reverse(A + l, A + r) 翻转区间 [l, r)。
sort(A + l, A + r) 排序区间 [l, r)。
unique(A + l, A + r) 把区间里连续的相同的元素移至末尾,返回剩下的元素结尾位置。
int m = unique(A, A + n) – A;
nth_element(A + l, A + k, A + r) 把 [l, r) 部分排序,使得 A[k] 这个位置的元素是正确的,比它小的在左边而比它大的在右边。
比如 nth_element(A, A + 5, A + 10) 会把第 6 小的(注意从 0 开始)放到 A[5],前 5 小以任意顺序放到 A[0...4],其他以任意顺序放到 A[6...9]
lower_bound(A + l, A + r, x) 返回第一个大于等于 x 的位置(要求序列有序)。取其下标可以 lower_bound(A + l, A + r, x) – A;
upper_bound 同理,返回第一个大于 x 的位置。
binary_search(A + l, A + r, x) 二分查找判断 x 是否在这个区间里出现,只返回true/false

posted @ 2019-08-04 11:05  pyyyyyy  阅读(331)  评论(0编辑  收藏  举报