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)\)

    • 写离散化时,可以先 uniqueerase,最后二分查找即可。

      	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

双端队列,但是支持随机访问。可以说,包含了所有vectorqueue的操作,还有其他一些操作,下面讲讲额外的操作。

  • 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)\) 的。

还有一种做法,将要删除的数放进桶里,然后每次判断堆顶元素是否需要删除,并做相关标记。但这种做法对值域的要求较为严苛,这里不在赘述。

posted @ 2022-11-20 23:47  2017BeiJiang  阅读(21)  评论(0编辑  收藏  举报