这个东西还蛮重要的。。。就是在考场上正解想不出来,打暴力需要用一些工具这时又发现忘了怎么用了,这就很尴尬了。。。
1.set
实用性很高,所以放最前面啦~
set
内部通常采用红黑树实现。平衡二叉树的特性使得 set
非常适合处理需要同时兼顾查找、插入与删除的情况。 ——摘自OI wiki
set
中的元素默认从小到大自动排序,但比起堆来支持的操作更多。 其中 multiset
支持插入重复数字,而 set
不能,除此以外操作基本相同。
指针
定义是这样式儿的:
set<int>::iterator it1;
multiset<int>::iterator it2;
set<pair<int,int> >::iterator it3;
支持 * 解除引用(就是将指针变为指针指向的东西)
it=s.lower_bound(val);
int x=*it;
set
的迭代器为双向访问迭代器 ,指针仅可以左移或右移(也就是 ++ 或 --),会移到从小到大排序该数的上/下一个,时间复杂度 。
it=--s.lower_bound(val);
函数
begin()/end()
begin()
返回首元素的迭代器,也就是指向首元素的指针,s.begin()
就是集合中最小的一个。
但由于 set
是左闭右开的,end()
返回的便是尾元素再向后一位的位置,或者说集合中最大元素的下一个位置的迭代器(引自算阶),也就是说是没有元素的,使用要注意。
rbegin()
与 rend()
是指向逆向数组的迭代器,通俗讲 rbegin()
end()
,rend()
begin()
。然并卵
函数名前加 c 为只读迭代器,通常情况下是等义的,例如 begin()
cbegin()
,end()
cend()
,但不能通过只读迭代器修改集合中的值(引自OI wiki)。
所以基本上会用begin()与end()就行 时间复杂度 。
insert()
插入操作。当使用 set
时如果插入的是重复数字,那么什么也不会发生,所以说有可重复的数字就要用 multiset
。时间复杂度 。
find()
在集合中查找等于 的元素,并返回指向该元素的迭代器。若不存在,则返回 s.end()
(引自算阶)。时间复杂度 。
erase()
可以调用指针,删去当前指针所引向元素,这样会删去一个元素。通常 s.erase(s.find(x))
配合食用。时间复杂度 。
也可以调用元素,删去这个值,这样会删去所有等于该元素的值,返回删除元素的个数。时间复杂度 ,其中 为被删除的元素个数。
还可以区间操作。erase(s,t)
删除迭代器在 范围内的所用元素(引自OI wiki)。
lower_bound()/upper_bound()
与平常用的一样,但只需要调用查找的关键值就行。函数返回值是迭代器,如果不存在,返回 s.end()
。时间复杂度 。
其他函数
size()
返回集合内元素个数。
empty()
返回集合是否为空,空返回,否则返回。
clear()
为清空操作。
count(x)
返回集合中的个数。
其他
自定义比较方式
特殊情况下用到。
struct cmp {
bool operator()(int a, int b) { return a > b; }
};
set<int, cmp> s;
(引自OI wiki) 这样就能实现从大到小排序了~
2.vector
vector 是 STL 提供的内存连续的、可变长度的数组(亦称列表)数据结构。能够提供线性复杂度的插入和删除,以及常数复杂度的随机访问。 ——摘自OI wiki
我们一般使用 vector
是因为它可以动态分配内存,空间有多大开多大,就可以在每个储存长度未知但总长度已知的情况下使用了。它也能支持很多操作。
指针
定义是这样式儿的:
vector<int>::iterator it
支持 * 解除引用。
vector
的指针能提供的骚操作更多,例如与一个整数相加减:
for(int i=1;i<=10;i++) v.push_back(i);
it=v.begin();
it+=2;
cout<<*it;
结果输出3。
把 vector
的两个指针(迭代器)相减,得到两个迭代器对应下标之间的距离:
for(int i=1;i<=10;i++) v.push_back(i);
it1=v.begin(),it2=--v.end();
cout<<it2-it1;
结果输出9。
函数
这里一些函数与 set
一样就不提啦。
front()/back()
front(
) 返回 vector
中的第一个元素,back()
返回最后一个元素。
push_back/pop_back()
在末尾插入/删除元素,时间复杂度为线性。
其他
放几个可能用的到的。
访问
at(pos)
返回容器中下标为 pos 的引用。如果数组越界抛出 std::out_of_range
类型的异常。
与直接数组访问同理,但不执行越界检查。
data()
返回指向数组第一个元素的指针。(引自OI wiki)。
长度
resize()
改变 vector
的长度,多退少补。改变之后就跟普通数组一样了。
v.resize(len);
max_size()
返回容器的最大可能长度。
cout<<v.max_size();
输出很怪的值:4611686018427387903。
3.map
map 是有序键值对容器,它的元素的键是唯一的。搜索、移除和插入操作拥有对数复杂度。map 通常实现为红黑树。 ——摘自OI wiki
就是哈希啦~ 懒得手写哈希可以用这个。
定义方式:
map<key_type,value_type> m;//key 和 value 可以是任意类型。
map<int,int> m;
map<pair(int,int),vector<int> > m1;
(引自算阶) map
的指针与 set
的指针类型是一样的,解除引用后,将得到一个二元组 pair<key_type,value_type>
。
函数
insert()/erase()
元素的插入/删除。insert()
的参数是 pair<key_type,value_type>
,erase()
的参数可以是 key 或者是迭代器(引自算阶)。
操作符
map
支持像数组那样的访问、查找。但如果查找的值不存在则会新建一个空的二元组,因此要配合 find()
/count()
使用。
map
还有其他函数,但不常用就不说了。
其他
unordered_map
无序关联式容器则采用哈希方式存储元素,内部元素不以任何特定顺序进行排序,所以访问无序关联式容器中的元素时,访问顺序也没有任何保证。 ——摘自OI wiki
因为没有排序,unordered_map
通常会比 map
快一些。但在特殊情况下会被卡,需要酌情使用。
4.bitset
一些卡内存的题可能用到。能够用很小的空间储存 串(每 位占一个字节),且支持操作多,十分方便。
bitset
的复杂度一般被认为是 ,其中 (计算机的位数)(引自OI wiki)。
话说 bitset
严格来讲并不属于 STL (大惊
定义方式:
bitset<4000> bit
其中 是 bitset 的位数。
位运算
~bit
按位取反。
&
|
^
与、或、异或。
<<
>>
左移右移。
支持数组下标读取方式。(下标从 开始)
s=13;
cout<<s<<endl;
s=~s;
cout<<s<<endl;
s>>=1;
cout<<s<<endl;
s^=1;
cout<<s<<endl;
cout<<s[3];
输出: 01101 10010 01001 01000 1
函数
count()
返回 的个数。
any()
: 若存在某一位是 则返回 ,否则返回 。
none()
: 若所有位都是 则返回 ,否则返回 。
set()
把所有位变为 。set(,) 把第 位改为 。
reset()
把所有位变为 。reset() 把第 位变为 。
flip()
把所有位取反,flip()同理(引自OI wiki 与 算阶)。
其他函数不常见就不写了~
5.queue
这个用法更简单了~ 来写一下 priority_queue
的用法。
用堆也可以实现很多操作,常用的如对顶堆。
priority_queue<int> q1//大根堆
priority_queue<int,vector<int>,greater<int> >q2//小根堆
小根堆也可以用重载小于号来实现。
更方便的用法是当成负数存进去~
如果是套 pair
的话会按第一位优先排序。
deque
是双端队列,支持头与尾的插入、弹出。