参考oi wiki
STL的产生是为了简化数据结构和算法的内部实现
并对任一数据类型都可实现对应操作
将功能封装起来,用时即拿
向量 vector 顺序表 可当作动态数组使用
数组 array C++11特性 定长顺序表(静态数组)
双端队列 deque 两端均可对数据元素进行高效操作的队列
列表 list 可沿双向遍历的链表 (双向链表)
单向列表(forward_list)只能单向遍历
集合 set 有序性 互异性 红黑树实现
多重集合 multiset 有序性 可重性
映射 map 键值对的集合 按键值有序排列
多重映射 multimap 键值对组成的多重集合 允许一个键有多个映射
无序集合 unordered_set 无序 哈希实现 关心元素是否存在
无序映射unordered_map 键无序 哈希实现 关心映射关系
适配器是对STL容器的包装,使其拥有和数据结构一样的作用
栈 stack LIFO容器 默认是对双端队列的包装
队列 queue FIFO容器 默认是对双端队列的包装
优先队列 priorty_queue 默认对向量包装
类似于数组的指针,迭代器可以访问容器中的元素
主要支持自增++,自减-- 来移动迭代器
以及*用来解引用
迭代器的声明
container::iterator it;
auto it;
迭代器在很多STL函数里作为参数
= //赋值 赋值构造
container_name.begin() //返回容器首个元素的迭代器
container_name.end() //返回末尾迭代器
container_name.size() //返回容器大小
container_name.empty() //判空
swap(container1,container2) <==> container1.swap(container2) //交换容器内容
container_name.clear() //清除
== != < > <= >= //字典序比大小 无序容器不支持
顺序表,内存连续,可变长度
随机访问,插删时间复杂度线性
向量容器内部重写了赋值与比较运算符,可以使用简单的双目运算符直接比较容器
vector底层依旧是定长数组,但分开存储了当前长度n与最大容量N,当检测到n>N,容器将分配2N数组,将旧数据拷贝到新数组,并释放原数组内存
vector对bool的特化,在vector
是对原生数组的直接封装
提供线性复杂度删插,随机访问
deque的底层是多个不连续的缓冲区buffer,但缓冲区内部内存连续,并记录首尾指针,用以标记有效数据区间,一个buffer满就会分配新的buffer
双向链表增删查改的操作与deque相同
不过链表不提供随机访问的接口,只能迭代器访问
含有键值对象的已排序集,支持对数复杂度的搜删插
内部实现是红黑树。拥有平衡二叉树的特性
有序键值对容器,键唯一,支持对数复杂度搜删插
通过红黑树实现
普通的关联容器大多通过红黑树实现,而无序关联式容器使用哈希方法
使得该类容器大部分操作都可以在常数复杂度进行
STL里,每个元素的散列值都是对这个列表里的质数取模得到
G++7后一般是107897
可通过向容器中插入该质数的倍数制造哈希冲突
为避免哈希冲突
需要先定义结构体,重载()运算符
struct my_hash {
size_t operator()(int x) const { return x; }
};
为确保哈希函数不被轻易破解,可在哈希函数中加入许多随机化函数
struct my_hash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM =
chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
// 针对 std::pair 作为主键类型的哈希函数
size_t operator()(pair x) const {
static const uint64_t FIXED_RANDOM =
chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x.first + FIXED_RANDOM) ^
(splitmix64(x.second + FIXED_RANDOM) >> 1);
}
};
自定义完后,就可以在声明容器时传入哈希函数了
栈和队列都是对双端队列的包装,但都对其进行了限制性操作
栈和队列均不支持随机访问与迭代器
其成员函数均为线性复杂度
对于优先队列,一般称作堆或者二叉堆
除了删插是对数复杂度外,其余常用成员函数皆是常数级别