C++_STL
C++ 标准模板库(Standard Template Library,STL)是一套功能强大的 C++ 模板类和函数的集合,它提供了一系列通用的、可复用的算法和数据结构。
STL 的设计基于泛型编程,这意味着使用模板可以编写出独立于任何特定数据类型的代码。STL 分为多个组件,包括容器(Containers)、迭代器(Iterators)、算法(Algorithms)、函数对象(Function Objects)和适配器(Adapters)等。
组件名 | 描述 |
---|---|
容器(Containers) | 用于存储和管理数据的类模板,提供了不同的数据结构,如序列式容器(如 vector 、list 、deque ),可以像数组一样顺序存储元素;关联式容器(如 map 、set ),基于键值对存储元素,通过键快速查找元素;无序容器(如 unordered_map 、unordered_set ),使用哈希表实现,能在平均 O (1) 的时间复杂度内进行元素的插入、查找和删除操作。 |
迭代器(Iterators) | 为容器提供了统一的访问接口,类似于指针,用于遍历容器中的元素。不同类型的容器有不同类型的迭代器,如正向迭代器、双向迭代器和随机访问迭代器,每种迭代器提供的操作不同,如随机访问迭代器支持像指针一样进行算术运算来访问容器中的元素。 |
算法(Algorithms) | 一系列通用的函数模板,用于处理容器中的数据。这些算法独立于容器的具体实现,通过迭代器来访问和操作容器中的元素,例如 sort 算法用于对容器中的元素进行排序,find 算法用于在容器中查找特定元素。 |
函数对象(Function Objects) | 是可调用的对象,本质上是重载了函数调用运算符 () 的类。函数对象可以像函数一样被调用,与普通函数相比,它可以保存状态,例如 std::less 是一个函数对象,用于比较两个元素的大小关系。 |
适配器(Adapters) | 用于修改或扩展其他组件的接口。例如容器适配器(如 stack 、queue ),它们基于其他容器(如 deque )实现了特定的数据结构接口;迭代器适配器(如 reverse_iterator )可以将迭代器的遍历方向反转;函数适配器(如 std::bind )可以将函数或函数对象的参数绑定到特定的值,改变函数的调用方式和参数列表。 |
-
容器(Containers)
容器分类 | 容器名称 | 描述 | 特点 | 适用场合 |
---|---|---|---|---|
序列式容器 | std::vector | 动态数组,其大小可以在运行时改变。元素在内存中连续存储。 | - 支持随机访问,可通过下标快速访问任意元素。 - 尾部插入和删除操作效率高,时间复杂度为 O(1)。 - 若中间或头部插入删除元素,需移动后续元素,效率低,时间复杂度为 O(n)。 | - 适合需要频繁随机访问元素的场景,如访问数组中的第 i 个元素。 - 元素主要在尾部进行插入和删除操作的场景,如存储用户输入的整数列表。 |
std::deque | 双端队列,支持在队列两端高效地插入和删除元素。 | - 支持随机访问,但效率略低于 std::vector 。- 两端插入和删除操作效率高,时间复杂度为 O(1)。 - 内部数据存储不是连续的,由多个固定大小的数组组成。 | - 适用于需要在两端频繁插入和删除元素的场景,如任务调度系统,新任务可在队首或队尾加入。 - 对随机访问有一定要求,但不如 std::vector 频繁的场景。 | |
std::list | 双向链表,由节点组成,每个节点包含元素值以及指向前一个和后一个节点的指针。 | - 不支持随机访问,访问元素需从头或尾开始遍历,时间复杂度为 O(n)。 - 任意位置插入和删除操作效率高,时间复杂度为 O(1)。 - 动态分配节点内存,内存开销较大。 | - 适合需要频繁在任意位置插入或删除元素的场景,如实现一个链表式的缓存。 - 不需要随机访问元素的场景。 | |
std::forward_list | 单向链表,每个节点只包含指向下一个节点的指针。 | - 只支持单向顺序访问,不支持反向遍历。 - 插入和删除操作比 std::list 更高效,因为只需要更新一个指针。- 不提供 size() 操作,因为维护大小信息会增加额外开销。 | - 适用于只需要单向遍历且对空间和插入删除性能有较高要求的场景,如实现简单的链表算法。 | |
关联式容器 | std::set | 存储唯一元素的容器,元素会根据其值自动排序。 | - 元素唯一,插入重复元素会被忽略。 - 基于红黑树实现,插入、删除和查找操作的时间复杂度为 O(logn)。 - 支持双向迭代器。 | - 需要快速查找元素是否存在,且元素不能重复的场景,如存储不重复的用户名。 - 对元素进行排序存储的场景。 |
std::multiset | 允许存储多个相同值的元素,元素同样会根据其值自动排序。 | - 可存储重复元素。 - 基于红黑树实现,插入、删除和查找操作的时间复杂度为 O(logn)。 - 支持双向迭代器。 | - 存储可重复元素,并且需要快速查找的场景,如存储学生成绩排名(可能有多个学生成绩相同)。 | |
std::map | 存储键值对的容器,每个键是唯一的,元素会根据键自动排序。 | - 键唯一,一个键只能对应一个值。 - 基于红黑树实现,插入、删除和查找操作的时间复杂度为 O(logn)。 - 支持双向迭代器。 | - 根据键快速查找对应值的场景,如实现字典,通过单词查找其释义。 | |
std::multimap | 允许一个键对应多个值的容器,元素会根据键自动排序。 | - 一个键可以对应多个值。 - 基于红黑树实现,插入、删除和查找操作的时间复杂度为 O(logn)。 - 支持双向迭代器。 | - 一个键对应多个值的场景,如存储一个课程对应的多个学生信息。 | |
容器适配器 | std::stack | 基于其他容器(默认 std::deque )实现后进先出(LIFO)的数据结构。 | - 只提供 push (入栈)、pop (出栈)、top (访问栈顶元素)等操作。- 封装底层容器,限制操作接口。 | - 递归算法的非递归实现,如模拟函数调用栈。 - 表达式求值,如逆波兰表达式计算。 |
std::queue | 基于其他容器(默认 std::deque )实现先进先出(FIFO)的数据结构。 | - 提供 push (入队)、pop (出队)、front (访问队首元素)、back (访问队尾元素)等操作。- 封装底层容器,限制操作接口。 | - 任务排队处理,如消息队列,先到的消息先处理。 - 广度优先搜索(BFS)算法。 | |
std::priority_queue | 基于其他容器(默认 std::vector )实现的优先队列,元素按照优先级出队。 | - 元素根据优先级排序,默认最大元素优先级最高,可自定义比较函数。 - 提供 push (插入元素)、pop (移除优先级最高的元素)、top (访问优先级最高的元素)等操作。 | - 优先处理重要任务的场景,如操作系统任务调度,高优先级任务先执行。 - Dijkstra 最短路径算法。 |
-
迭代器(Iterators)
迭代器名称 | 描述 | 特点 | 适用场合 |
---|---|---|---|
输入迭代器(Input Iterator) | 用于从序列中读取元素,支持 ++ 操作向前移动,可进行比较和解引用操作访问元素,但只能进行单向、单次遍历,不保证对同一位置的多次访问一致性。 | 单向、单次读取,不支持元素修改,操作相对简单。 | 适用于只需对序列进行一次只读遍历的场景,如 std::find 、std::count 等算法,用于查找或统计元素。 |
输出迭代器(Output Iterator) | 用于向序列中写入元素,支持 ++ 操作向前移动,解引用后可对元素进行赋值操作,同样是单向、单次使用。 | 单向、单次写入,不支持元素读取,仅用于输出数据。 | 常用于将数据输出到某个序列的场景,例如 std::copy 算法将元素复制到目标序列时的输出端。 |
正向迭代器(Forward Iterator) | 具备输入迭代器的所有功能,并且可以多次读取同一个元素,保证在遍历过程中对元素的多次访问是安全的,支持多次单向遍历。 | 单向、可重复读取,支持简单的读写操作。 | 适用于需要对序列进行多次遍历,且每次遍历都从序列开头开始的情况,比如某些统计操作,可能需要多次遍历容器来计算不同的统计量。 |
双向迭代器(Bidirectional Iterator) | 在正向迭代器的基础上,增加了向后移动的功能,支持 -- 操作来移动到前一个元素。 | 双向移动,可重复读写,功能更强大。 | 当需要在序列中双向遍历的场景,例如双向链表中,既可以向前查找元素,也可能需要向后回溯查找其他元素。 |
随机访问迭代器(Random Access Iterator) | 支持随机访问元素,可以像指针一样进行偏移操作,如 it + n 、it - n ,还支持比较两个迭代器之间的距离、[] 操作符访问元素等。 | 随机访问,操作灵活,效率高。 | 适用于需要快速随机访问元素的容器,如 std::vector 和 std::deque 。在排序、二分查找等需要频繁随机访问元素的算法中,随机访问迭代器能提供高效的支持。 |
反向迭代器(Reverse Iterator) | 是一种特殊的迭代器适配器,它以相反的顺序遍历序列,从序列的末尾开始,向前移动到序列的开头。通过 base() 成员函数可获取对应的正向迭代器。 | 反向遍历,与正向迭代器相互转换。 | 当需要反向遍历容器时使用,比如从后往前输出容器中的元素,或者在一些需要从后往前处理数据的算法中使用。 |
-
算法(Algorithms)
算法分类 | 算法名称 | 描述 | 特点 | 适用场合 |
---|---|---|---|---|
非修改序列算法 | std::for_each | 对指定范围内的每个元素应用给定的函数 | 不修改元素值,顺序遍历元素 | 对容器元素进行统一处理,如打印元素、更新元素非值属性 |
std::find | 在指定范围内查找等于给定值的第一个元素 | 线性查找,返回迭代器 | 确定容器中是否存在某个特定值 | |
std::find_if | 在指定范围内查找满足给定条件的第一个元素 | 线性查找,可自定义条件 | 查找符合特定条件的元素,如第一个负数 | |
std::count | 统计指定范围内等于给定值的元素个数 | 线性遍历计数 | 统计容器中特定值出现的次数 | |
std::count_if | 统计指定范围内满足给定条件的元素个数 | 线性遍历计数,可自定义条件 | 统计符合特定条件的元素数量,如偶数个数 | |
修改序列算法 | std::copy | 将一个范围的元素复制到另一个范围 | 按顺序复制元素 | 复制容器元素到另一个容器 |
std::move | 将一个范围的元素移动到另一个范围 | 资源转移,避免不必要复制 | 高效转移资源,如移动对象所有权 | |
std::swap | 交换两个元素的值 | 简单交换操作 | 排序等算法中交换元素位置 | |
std::fill | 用给定值填充指定范围的元素 | 统一赋值 | 初始化容器元素为特定值 | |
std::transform | 对范围内的元素应用函数,结果存于另一个范围 | 可自定义转换操作 | 批量转换容器元素,如元素值加倍 | |
排序和相关算法 | std::sort | 对指定范围的元素进行排序 | 通常是快速排序,不稳定排序 | 对容器元素进行升序或自定义排序 |
std::stable_sort | 对指定范围的元素进行稳定排序 | 保持相等元素相对顺序,效率略低 | 排序时需保持相等元素顺序的场景 | |
std::partial_sort | 对指定范围的部分元素进行排序 | 只排前 n 个元素 | 找出前 n 个最小或最大元素 | |
std::nth_element | 重新排列范围,使第 n 个元素处于排序位置 | 不保证其他元素有序 | 找到第 n 小(大)的元素 | |
std::binary_search | 在有序范围内查找是否存在给定值 | 二分查找,效率高 | 在已排序容器中快速查找元素 | |
集合算法 | std::set_union | 计算两个有序范围的并集 | 结果也是有序的 | 合并两个集合,去除重复元素 |
std::set_intersection | 计算两个有序范围的交集 | 结果有序 | 找出两个集合的共同元素 | |
std::set_difference | 计算两个有序范围的差集 | 结果有序 | 找出在一个集合但不在另一个集合的元素 | |
std::set_symmetric_difference | 计算两个有序范围的对称差集 | 结果有序 | 找出只在一个集合中出现的元素 | |
数值算法 | std::accumulate | 计算指定范围内元素的总和 | 可指定初始值 | 计算容器元素总和 |
std::inner_product | 计算两个范围的内积 | 可指定初始值 | 数学计算中的向量内积等 | |
std::partial_sum | 计算指定范围内元素的部分和 | 结果存于另一个范围 | 生成前缀和数组 | |
std::adjacent_difference | 计算指定范围内相邻元素的差值 | 结果存于另一个范围 | 分析数据变化趋势 | |
堆算法 | std::make_heap | 将指定范围的元素转换为堆 | 满足堆的性质 | 初始化堆结构 |
std::push_heap | 将一个元素插入到堆中 | 维护堆的性质 | 动态添加元素到堆中 | |
std::pop_heap | 从堆中移除最大(小)元素 | 维护堆的性质 | 动态移除堆顶元素 | |
std::sort_heap | 将堆转换为有序序列 | 堆排序 | 对堆中的元素进行排序 | |
排列算法 | std::next_permutation | 生成指定范围元素的下一个排列 | 按字典序生成 | 生成全排列,用于搜索所有组合 |
std::prev_permutation | 生成指定范围元素的上一个排列 | 按字典序逆序生成 | 逆序生成排列 |
-
函数对象(Function Objects)
函数对象名称 | 描述 | 特点 | 适用场合 |
---|---|---|---|
std::plus<T> | 执行两个对象的加法操作,返回它们的和,即 x + y | 简单直接,可用于各种支持加法运算的数据类型,运算逻辑固定为加法 | 数值求和,如计算容器内所有元素的总和;在一些需要对元素进行累加操作的算法中使用 |
std::minus<T> | 对两个对象执行减法操作,得到差值 x - y | 功能单一,专注于减法运算,适用于支持减法的数据类型 | 计算差值,像计算两个时间点的间隔、容器中相邻元素的差值等 |
std::multiplies<T> | 实现两个对象的乘法运算,结果为 x * y | 适用于可进行乘法运算的类型,逻辑清晰为乘法 | 计算乘积,例如计算数组元素的累积乘积;在某些数学计算场景中使用 |
std::divides<T> | 对两个对象做除法运算,返回 x / y | 进行除法操作,要求除数不为零,适用于支持除法的数据类型 | 在需要进行除法计算的场景中使用,如计算平均值时的分母操作 |
std::modulus<T> | 返回两个对象相除后的余数,即 x % y | 执行取模运算,要求操作数为整数类型 | 用于需要取模的场景,如判断奇偶性、哈希函数中的取模操作 |
std::negate<T> | 对单个对象取负,得到 -x | 操作单个对象,将其变为相反数,适用于支持取负运算的类型 | 对数据进行取负处理,如在数学计算中改变数值的符号 |
std::equal_to<T> | 判断两个对象是否相等,返回 x == y 的结果 | 用于相等性判断,比较逻辑基于 == 运算符 | 在查找、筛选操作中,判断元素是否等于某个特定值 |
std::not_equal_to<T> | 判断两个对象是否不相等,返回 x != y 的结果 | 与 equal_to 相反,基于 != 运算符进行比较 | 用于查找不满足相等条件的元素 |
std::greater<T> | 比较两个对象,若 x > y 则返回 true | 基于 > 运算符,用于降序排序或比较大小 | 在排序算法中指定降序排序规则;在优先级队列中设置高优先级元素在前的规则 |
std::less<T> | 比较两个对象,当 x < y 时返回 true | 基于 < 运算符,常用于升序排序和比较 | 默认的排序准则,大多数排序算法默认使用该函数对象进行升序排列 |
std::greater_equal<T> | 判断 x >= y 是否成立,返回相应布尔值 | 基于 >= 运算符进行比较 | 在需要判断一个元素是否大于等于另一个元素的场景中使用 |
std::less_equal<T> | 判断 x <= y 是否成立,返回相应布尔值 | 基于 <= 运算符进行比较 | 用于判断元素小于等于关系的场景,如范围检查 |
std::logical_and<T> | 对两个布尔值执行逻辑与操作,返回 x && y 的结果 | 用于逻辑与运算,操作布尔类型对象 | 在需要同时满足多个条件的筛选操作中使用 |
std::logical_or<T> | 对两个布尔值执行逻辑与操作,返回 x && y 的结果 | 用于逻辑或运算,操作布尔类型对象 | 在满足多个条件中任意一个即可的筛选场景中使用 |
std::logical_not<T> | 对单个布尔值取反,返回 !x 的结果 | 对单个布尔值进行取反操作 | 在需要反转条件判断结果的场景中使用 |
-
适配器(Adapters)
适配器类型 | 适配器名称 | 描述 | 特点 | 适用场合 |
---|---|---|---|---|
容器适配器 | std::stack | 基于其他容器(默认std::deque )实现后进先出(LIFO)的数据结构,提供push (入栈)、pop (出栈)、top (访问栈顶元素)等操作 | 封装底层容器,限制操作接口,只能在栈顶进行元素的插入和删除 | 函数调用栈模拟、表达式求值(如逆波兰表达式计算)、回溯算法等 |
std::queue | 基于其他容器(默认std::deque )实现先进先出(FIFO)的数据结构,提供push (入队)、pop (出队)、front (访问队首元素)、back (访问队尾元素)等操作 | 封装底层容器,限制操作接口,元素从队尾插入,从队首删除 | 任务调度系统(如作业队列)、消息传递系统、广度优先搜索(BFS)算法 | |
std::priority_queue | 基于其他容器(默认std::vector )实现的优先队列,元素按照优先级出队,提供push (插入元素)、pop (移除优先级最高的元素)、top (访问优先级最高的元素)等操作 | 元素根据优先级排序,默认最大元素优先级最高,可自定义比较函数 | 操作系统中的任务调度(优先处理重要任务)、Dijkstra 最短路径算法等 | |
迭代器适配器 | std::reverse_iterator | 反转迭代器的遍历方向,将正向迭代器转换为反向迭代器,通过base() 成员函数可获取对应的正向迭代器 | 提供反向遍历容器的能力,不改变容器本身的存储顺序 | 需要从容器末尾向开头遍历元素的场景,如逆序输出容器元素 |
std::back_insert_iterator | 用于在容器尾部插入元素的迭代器,通过重载operator= 实现元素插入 | 可自动扩展容器容量,保证元素插入到容器尾部 | 当需要将元素插入到可增长容器(如std::vector )的末尾时使用 | |
std::front_insert_iterator | 用于在容器头部插入元素的迭代器,通过重载operator= 实现元素插入 | 对于支持头部插入的容器(如std::list 、std::deque )有效 | 在需要频繁在容器头部插入元素的场景中使用 | |
std::insert_iterator | 可在容器指定位置插入元素的迭代器,通过重载operator= 实现元素插入 | 可在任意位置插入元素,需要提供插入位置的迭代器 | 在容器的特定位置插入元素的场景 | |
函数对象适配器 | std::bind | 用于将可调用对象(函数、函数指针、成员函数指针等)与参数进行绑定,生成一个新的可调用对象,可以绑定部分参数或全部参数,还能调整参数顺序 | 提高代码的灵活性和复用性,可延迟调用可调用对象 | 当需要将一个函数适配到另一个需要不同参数列表的函数接口时使用,或者需要固定部分参数值进行多次调用 |
std::function | 通用的多态函数包装器,可存储、复制和调用任何可调用对象,包括函数、函数指针、成员函数指针、函数对象等 | 类型擦除,统一不同类型的可调用对象的调用方式 | 在需要将不同类型的可调用对象作为参数传递或存储在容器中的场景 | |
std::mem_fn | 用于包装成员函数,使其可以像普通函数一样被调用,可以直接调用成员函数,而无需显式提供对象指针或引用 | 简化成员函数的调用,提高代码可读性 | 在算法中需要调用对象的成员函数时使用,避免手动处理对象指针或引用 |