【C++ STL】标准模板库


参考资料
https://hackingcpp.com/index.html
https://oi-wiki.org/

STL概述

C++ STL(标准模板库,Standard Template Library)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构。

STL 提供了六大组件,彼此组合套用协同工作。这六大组件分别是:

  • 容器(Containers):各种数据结构,如vector、list、deque、set、map等。
    从实现的角度来看,STL容器是一种 class template。
  • 算法(Algorithms):各种常用算法,提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作,比如 sort、search、copy、erase。
    从实现的角度来看,STL算法是一种 function template。
  • 迭代器(Iterators):迭代器用于遍历对象集合的元素,扮演容器与算法之间的胶合剂,是所谓的“泛型指针”,共有 5 种类型,以及其他衍生变化。所有的 STL 容器附带有自己专属的迭代器,因为只有容器设计者才知道如何遍历自己的元素。
    从实现角度来看,迭代器是一种将 operator*、operator->、operator++、operator-- 等指针操作予以重载的 class template。
  • 仿函数(Functors):也称为函数对象(Function object),行为类似函数,可作为算法的某种策略。
    从实现角度来看,仿函数是一种重载了 operator() 的 class 或者 class template。
  • 适配器(Adaptors):一种用来修饰容器或者仿函数或迭代器接口的东西。例如 STL 提供的 queue 和 stack,就是一种空间配接器,因为它们的底部完全借助于deque。
  • 分配器(Allocators):也称为空间配置器,负责空间的配置与管理。从实现的角度来看,配置器是一个实现了动态配置空间、空间管理、空间释放的 class template。
    在这里插入图片描述

使用STL的好处:

  • STL是C++的一部分,因此不用额外安装,它被内置在编译器之内。
  • STL的一个重要特点是数据结构和算法的分离。(内部使用的模板,即泛型编程)
  • 程序员可以不用思考STL具体的实现过程,只要能够熟练使用STL,把精力用在开发上。
  • STL具有高可重用性、高性能、高移植性、跨平台等优点
    • 高可重用性: STL中几乎所有的代码的采用了模板类和模板函数的方式实现,这相当于传统的由函数和类组成的库来说提供了更好的代码重用机会。
    • 高性能:底层使用的数据结构和算法比较优秀,如map是使用红黑树的变体实现的。(红黑树是平衡二叉树的一种)
    • 高移植性:因为是内建在编译器之内,项目A中用STL编写的模块可以直接移植到项目B上。
    • 跨平台:windows上写的可以在Linux上运行。(反之亦可)

STL从广义上讲分为三类: iterator(迭代器)、container(容器)、algorithm(算法) 。容器和算法可以通过迭代器进行无缝的连接。

迭代器

  • 什么是迭代器:

    迭代器是一种检查容器内元素并且遍历容器内元素的数据类型

  • 迭代器的作用:

    迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。

  • 为什么需要迭代器:

    • STL提供每种容器的实现原理各不相同,如果没有迭代器,我们需要记住每一种容器中对象的访问方法,这样会变得非常麻烦。
    • 每个容器中都实现了一个迭代器用于对容器中对象的访问,虽然每个容器中的迭代器的实现方式不一样,但是对于用户来说操作方法是一致的,也就是说通过迭代器统一了对所有容器的访问方式
    • 无论哪个容器,访问当前元素的下一个元素我们都可以通过迭代器自增进行访问。
    • 迭代器是为了提高编程效率而开发的

容器

在这里插入图片描述

序列式容器

序列式容器(Sequence containers)就是将一组具有相同类型的元素以严格的线性形式组织起来。每个元素都有固定的位置,取决于插入的时机和地点,和元素值无关。

  • 数组(array) 定长的顺序表,C 风格数组的简单包装。(C++11)
  • 向量(vector) 动态数组/可变大小数组,后端可高效增加元素的顺序表。
  • 双端队列(deque) 双端都可高效增加元素的顺序表。
  • 列表(list) 可以沿双向遍历的链表。
  • 单向列表(forward_list) 只能沿一个方向遍历的链表,相比于list减小了空间开销。(C++11)

关联式容器

关联式容器(Associated containers) 元素位置取决于特定的排序准则,和插入顺序无关。

  • 集合(set) 用以有序地存储互异元素的容器。其实现是由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种比较元素大小的谓词进行排列。
  • 多重集合(multiset) 用以有序地存储元素的容器。允许存在相等的元素。
  • 映射(map) 由 {键,值} 对组成的集合,以某种比较键大小关系的谓词进行排列。
  • 多重映射(multimap) 由 {键,值} 对组成的多重集合,允许键有相等情况的映射。

无序(关联式)容器

  • 无序(多重)集合(unordered_set/unordered_multiset) 与 set/multiset 的区别在于元素无序,只关心「元素是否存在」,使用哈希实现。
  • 无序(多重)映射(unordered_map/unordered_multimap) 与 map/multimap 的区别在于键 (key) 无序,只关心 “键与值的对应关系”,使用哈希实现。(C++11)

容器适配器

  • 栈(stack) 后进先出 (LIFO) 的容器,默认是对双端队列(deque)的包装。
  • 队列(queue) 先进先出 (FIFO) 的容器,默认是对双端队列(deque)的包装。
  • 优先队列(priority_queue) 元素的次序是由作用于所存储的值对上的某种谓词决定的的一种队列,默认是对向量(vector)的包装。

共有函数

  • =:有赋值运算符以及复制构造函数。
  • begin():返回指向开头元素的迭代器。
  • end():返回指向末尾的下一个元素的迭代器。end() 不指向某个元素,但它是末尾元素的后继。
  • size():返回容器内的元素个数。
  • max_size():返回容器 理论上 能存储的最大元素个数。依容器类型和所存储变量的类型而变。
  • empty():返回容器是否为空。
  • swap():交换两个容器。
  • clear():清空容器。

特殊类

  • 位集合(bitset) 存储 0/1 的大小不可变容器 。

    严格来讲,bitset 并不属于 STL,而是一种标准库中的 “Special Container”。
    事实上,它作为一种容器,并不满足 STL 容器的要求(没有迭代器)。说它是适配器,它也并不依赖于其它 STL 容器作为底层实现。
    与类似的 vector<bool> 类不同,bitset大小固定,该大小在编译时根据声明 bitset<N> 时由模板参数 N 指定的大小确定并固定。
    如果某个位的值为 1,则该位已设置;如果其值为 0,则该位已重置。 翻转或反转某个位就是将其值从 1 更改到 0 或从 0 到 1。 bitset 中的 N 个位由从 0 到 N - 1 的整数值索引,其中 0 索引第一个位的位置,N - 1 索引最后一个位的位置。

  • 字符串(string)
  • 对组(pair)
  • 元组(tuple)

算法

STL 提供了大约 100 个实现算法的模版函数,基本都包含在 <algorithm> 之中,还有一部分包含在 <numeric><functional>中。

  • accumulate:对一个序列的元素求和。O(N)
    accumulate(v.begin(), v.end(), init),其中init为对序列元素求和的初始值

  • find:顺序查找。
    find(v.begin(), v.end(), value),其中 value 为需要查找的值。

  • fill:对一个序列进行初始化赋值。O(N)
    fill(v.begin(), v.end(), num)

    注意区分memset:memset()是按字节进行赋值,对于初始化赋0或-1有比较好的效果.如果赋某个特定的数会出错,赋值特定的数建议使用fill()

  • reverse:翻转数组、字符串。O(N)
    reverse(v.begin(), v.end())reverse(a + begin, a + end)

  • unique:去除容器中相邻的重复元素。
    unique(ForwardIterator first, ForwardIterator last),返回值为指向去重后容器结尾的迭代器,原容器大小不变。与 sort 结合使用可以实现完整容器去重。

  • sort:排序。O(NlogN)
    sort(v.begin(), v.end(), cmp)sort(a + begin, a + end, cmp),其中 end 是排序的数组最后一个元素的后一位,cmp 为自定义的比较函数。

  • stable_sort:稳定排序,用法同 sort()。

  • is_sorted

  • atoi atoi(const char *)

  • stoi stoi(const string*)

    将字符串转换为int类型
    atoi不做范围检查,如果超出上界,输出上界,超出下界,输出下界。
    stoi会做范围检查,默认必须在int范围内,如果超出范围,会出现RE(Runtime Error)错误。

  • iota

  • to_string 将数字转化为字符串,支持浮点数

  • random_shuffle shuffle:随机地打乱数组。
    shuffle(v.begin(), v.end(), rng)最后一个参数传入的是使用的随机数生成器。

    random_shuffle 自 C++14 起被弃用,C++17 起被移除。
    在 C++11 以及更新的标准中,可以使用 shuffle 函数代替原来的 random_shuffle。

  • nth_element:按指定范围进行分类,即找出序列中第 n 大的元素,使其左边均为小于它的数,右边均为大于它的数。
    nth_element(v.begin(), v.begin() + mid, v.end(), cmp)nth_element(a + begin, a + begin + mid, a + end, cmp)

  • binary_search:二分查找。
    binary_search(v.begin(), v.end(), value),其中 value 为需要查找的值。

  • transform

  • merge:将两个(已排序的)序列 有序合并 到第三个序列的 插入迭代器 上。
    merge(v1.begin(), v1.end(), v2.begin(), v2.end() ,back_inserter(v3))

  • inplace_merge:将两个(已按小于运算符排序的):[first,middle), [middle,last) 范围 原地合并为一个有序序列。
    inplace_merge(v.begin(), v.begin() + middle, v.end())

  • lower_bound:在一个有序序列中进行二分查找,返回指向第一个 大于等于 x 的元素的位置的迭代器。如果不存在这样的元素,则返回尾迭代器。
    lower_bound(v.begin(),v.end(),x)

  • upper_bound:在一个有序序列中进行二分查找,返回指向第一个 大于 x 的元素的位置的迭代器。如果不存在这样的元素,则返回尾迭代器。
    upper_bound(v.begin(),v.end(),x)

  • next_permutation:将当前排列更改为 全排列中的下一个排列。如果当前排列已经是 全排列中的最后一个排列(元素完全从大到小排列),函数返回 false 并将排列更改为 全排列中的第一个排列(元素完全从小到大排列);否则,函数返回 true。
    next_permutation(v.begin(), v.end()) 或 next_permutation(v + begin, v + end)

  • prev_permutation:将当前排列更改为 全排列中的上一个排列。用法同 next_permutation。

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值