STL笔记
在c++中,提供了许多实用的数据结构,称作STL,在考试时拿来用即可,非常方便,下面讲讲常见的STL。
Vector
vector ,又称动态数组,每次往里面丢一个数会申请一定空间,而不是在一开始全部申请,如果对空间大小把握不明确,可以使用 vector 替代数组,常见的应用有邻接表等。
支持随机访问,如可以直接 a[10] ,表示动态数组的第11个位置(下标默认从0开始)。
定义STL:vector<int> s; (定义一个一维动态数组,整形)。
基本操作(按照使用频率从上往下排序):
-
push_back(x):在数组的尾部插入一个元素x,时复 \(O(1)\). 注意下标从 \(0\) 开始。 -
size():返回当前动态数组的长度。 -
clear():清空动态数组。 -
begin(),end()- 功能:分别返回头,尾指针
- 应用:排序,二分查找,去重等。
-
erase-
erase(a,b):删除[a,b)中的元素,其中a,b是两个迭代器。 -
erase(a):删除位置a上的元素,其中a是迭代器。 -
时间复杂度:\(O(n)\)
-
写离散化时,可以先
unique再erase,最后二分查找即可。int find(int x) { //这样写,从1开始编号 return lower_bound(s.begin(), s.end(), x) - s.begin() + 1; } sort(s.begin(), s.end()); it = unique(s.begin(), s.end()); s.erase(it, s.end());
-
Queue
又称队列,实现的操作较少,但在广搜时还是很好用的。
常见操作:
push(x):往队尾插入x元素,\(O(1)\).front():取出队首元素。pop():弹出队尾元素。size():返回大小(长度)。empty():判断队列是否为空。
注意,queue 没有清空操作,所以清空时,需要:while(q.size()) q.pop();
Deque
双端队列,但是支持随机访问。可以说,包含了所有vector和queue的操作,还有其他一些操作,下面讲讲额外的操作。
push_front(x):往队头插入数字x。pop_front():删除队头元素。push_back(x):往队尾插入数字x。pop_back():删除队尾元素。
上述操作均为 \(O(1)\) ,不过在常数上稍微劣于vector(只用push_back)。
说完线性表STL,下面说说有关高级数据结构的STL。
Set
Set,顾名思义“集合”,内部采取红黑树实现,是一种有序数据结构,其中不会出现重复的元素。默认从小到大排序。
基本操作:
-
insert(x):插入元素x。 -
erase(x)- 如果
erase里面加的是元素而不是迭代器,就会删除所有值为x的元素,不过这在set中影响不大,毕竟set每个数值的元素只会出现一次。 - 如果
erase里面加的是迭代器,那么就删除对应位置上的元素即可。
- 如果
-
find(x):查找元素 \(x\),找到了返回迭代器,找不到返回.end()。 -
lower_bound(x):二分查找大于等于元素x的第一个数,返回迭代器,如果找不到,返回s.end()。 -
upper_bound(x):找到第一个大于x的数,剩下同上。 -
s.rbegin():反向迭代器。其实就是返回末尾元素的迭代器,一定要和s.end()区分开,s.end()是返回末尾元素的后一个位置,并不是末尾元素。 -
s.count(x):查找元素x出现了多少次,在set中最多出现一次,所以用这个函数检验是否存在元素也是可行的。 -
s.clear():清空集合。 -
访问。
set的访问其实比较蛋疼,不支持随机访问,只能用迭代器一个个走。像这样:set<int>::iterator it; for(it = s.begin(); it != s.end(); it++) *it; // *it 就是当前元素不过现在支持的
c++11标准可以这样做:for(auto x : s) x; //x就是当前元素是不是简洁很多。。。
Multiset
和Set类似,不过这个是可重集。
Map
也是相当实用的STL,甚至我最开始接触的STL就是map。
map一般是当成桶用,即如果要记录一些信息,用map就可以处理值域过大的问题。
这样定义:map<数据类型1,数据类型2> s;
数据类型1表示数组括号里面的类型,即 s[数据类型1] ,数据类型2就表示储存的值。
函数也不多,主要用的:
clear():清空。count():数数。
map的用途比较广泛,比如可以和字符串哈希一起用,以省去写哈希表的代码。但是要注意,不能直接写 map<string,int>s ,然后直接将字符串丢进map里面,这样还是会超时,需要先将字符串算成 unsigned long long 的哈希值,在丢进 map<ULL,int> s 的map里面。
如果记忆化搜索的状态比较复杂,可以考虑用 map 进行储存。
unordered_map
\(c++11\) 标准下的哈希表,一般来讲效率高于 map.
Priority_queue
优先队列,内部用堆实现,可以进行查询最值,插入的功能,虽然功能少于set,但是常数很小,比较优秀。
常见操作:
push(x):往堆里插入元素x.pop():弹出堆顶元素。top():返回堆顶元素。
由于堆不支持随机删除,所以可以使用两个堆,一个储存原来的数(记作 heap1),一个储存要删除的数(记作 heap2),如果 heap1 的堆顶和 heap2 的堆顶元素一致,说明当前元素是要删除的元素,两个堆都弹出即可。这样删除的复杂度是 \(O(\log n)\) 的。
还有一种做法,将要删除的数放进桶里,然后每次判断堆顶元素是否需要删除,并做相关标记。但这种做法对值域的要求较为严苛,这里不在赘述。

浙公网安备 33010602011771号