C++ 容器
标准库
- STL
内的所有基于比较的容器,都需要定义一个满足严格弱序的比较符号
<,要求如下:- 满足传递性:\(a<b,b<c\rightarrow a<c\)
- 不能同时满足 \(a<b\) 且 \(b<a\)
- 如果
!(a<b)&&!(b<a)那么a=b
- 除开
array之外的所有STL容器,定义时都会初始化,即初始化为空或者(全为0,对于bitset)。 - 基于比较的容器,需要定义友元类型的大小比较符号,因为实现的时候使用了右值做比较。
priority_queue
默认是大根堆,跑得很快,1 秒 \(3\times 10^6\)
如果需要实现可以删除的优先队列,必须保证每次删除时对应元素存在。
构造方式
priority_queue<type,container,cmp>,container
是实现 priority_queue 的容器,一般用
vector,cmp
是比较算子(因此它是一个类名)。
通过 greater<typename> 可以用重载的
> 构造出一个大于算子。
map
本质上是 set<pair<T1,T2>>,见
set。
set
insert
可以插入一段区间,支持数组,同类型的 set vector
容器。
开 O2,\(1\) 秒 \(1.5\times 10^6\) 次操作。
如果接下来的一段插入有序,开 O2,\(1\) 秒 \(4.5\times 10^6\) 次,所以尽量排序后再插入。
erase
开 O2,\(1\) 秒 \(1.5\times 10^6\) 次操作。
如果接下来的一段插入有序,开 O2,\(1\) 秒 \(4.5\times 10^6\) 次。
迭代器操作
开 O2,\(1\) 秒 \(10^7\)。
遍历
1 | for(auto v:st) |
以上两种均为 \(O(n\log n)\)
开 O2,\(1\) 秒 \(10^7\) 次操作。
unordered_set
基础操作相比 set 快 \(2\) 倍。
有序操作和 set 效率差不多。
unoedered_map
本质上是 unordered_set<pair<T1,T2>>。
vector
比较理想的一个容器。
push_back()
一个 vector 做 push_back 需要
log 次 new,而 new
操作一般只能接受 \(2\times 10^7\)
次,所以尽量避免用太多 vector,如果能事先确定容器的
capacity,最好用 resize
iterator insert(iterator,val)
将 val 插入 iterator 位置,原
iterator 位置往后移动。
复杂度 \(O(n)\),但是跑得飞快。
iterator erase(iterator)
删除 iterator 位置的值,返回原容器(删除前)下一个位置的
iterator。
iterator
这东西的迭代器本质上是个指针,但是不能和指针做强转,所以
iterator 在被 erase 后会指向错误的数据,不同于
set 这一类基于 RBT 的容器。
内存过程
调用析构函数之前,vector
的内存不可能被释放,push_back 或者 resize
如果导致了内存改变,会开辟一块新的内存并将原有数据全部拷贝过去,保证内存地址的连续,同时原有迭代器全部失效。
vector 所有的 \(O(n)\)
操作都很快,如果题目性质决定了很可能 \(O(n^2)\) 卡不满,那么 vector
可以得到很高的分数。
拓展库
一个 C++ 拓展库,STL
升级版,C++11 特性。
gp_hash_table
Introduction
如名称,哈希表,比 unordered_map 快 3~4
倍,用法完全一样,你值得拥有。
效率 1S 能做 4e7 次基本操作
在 ext/pb_ds/assoc_container.hpp 中。
如果对非标准结构,例如类和 pair
,容器等,需要自己写哈希方法,哈希方式为一个类,重载了 ()
运算,该重载必须被声明为常函数,且参数必须为常值引用。
1 |
|
Tests:
这里只放关键部分,其余实现见代码
测试环境为 Windows10,CPU 型号为 Inter I7-9750H,内存 16GB, 2667Mhz
命中率对速度影响:
1 | gen_data(1e6,4e7,8,7);//hit rate:87.5% |
插入和查询次数调整:
1 | gen_data(2e6,4e7,4,1); //插入 2e6 |
插入很多,查询很少。
1 | gen_data(2e7,4e6,50,1); |
其实插入操作比较慢是正常的,内存占用大了之后自然就慢了。
另外,手写哈希表探测法还有救,拉链法直接抬走(你写代码的时候考虑过 CPU cache 的感受吗?)。
插入较少且全部在查询前面 cc_hash_table 的效率优于
gp_hash_table。
Tree
虽然有这个东西,但是还是应该学习如何写平衡树。
效率还可以,开 O2 和以前手写差不多,估计现在手写的会快一些,不过问题不大。