【C++】标准模板库(STL)

目录

一、什么是 STL?

二、STL 的内容

2.1 STL 六大组件

2.2 容器

2.3 算法

2.4 适配器

2.4.1 stack

2.4.2 queue & priority_queue

三、STL 的使用场景

3.1 向量 vector

3.2 双端队列 deque

3.3 vector 与 deque 的比较(数组和链表的特性区别)

3.4 队列 list

3.5 集合 set

3.6 映射 map

3.7 对 vector、set、map 的区分

四、常用容器用法介绍


一、什么是 STL?

       标准模板库 STL(Standard Template Library),是 C++ 标准库的一部分,不需要单独安装,只需要 #include 头文件。

       STL 的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL 变得非常通用。例如,由于 STL 的 sort() 函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表、容器和数组;

       STL 的另一个重要特性是它不是面向对象的。STL 主要依赖于模板而不是封装、继承和虚函数(多态性)—— OOP的三个要素。在 STL 中找不到任何明显的类继承关系,但这正好是使得 STL 的组件具有广泛通用性的底层特征。另外,STL 是基于模板(Template)实现的,只换类型,不换方法,内联函数的使用使得生成的代码短小高效;

       C++ 语言的核心优势之一就是便于软件的复用,它在两个方面体现了复用:

  • 面向对象的继承和多态机制
  • 通过模板的概念实现了对泛型程序设计的支持

二、STL 的内容

2.1 STL 六大组件

  • 容器(Container):各种数据结构,如 vector、list、deque、set、map 等,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器;
  • 算法(Algorithm):各种常用算法,提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作,如 sort、find、copy、erase 函数等。函数本身与它们操作的数据的结构和类型无关,因此它们可以在从简单数组到高度复杂容器的任何数据结构上使用;
  • 迭代器(Iterator):迭代器提供了访问容器中对象的方法,扮演容器与算法之间的胶合剂,是所谓的“泛型指针”,共有 5 种类型,以及其他衍生变化,是一种将 operator*、operator->、operator++、operator-- 等指针操作予以重载的模板类。所有的 STL 容器附带有自己专属的迭代器,因为只有容器设计者才知道如何遍历自己的元素;
  • 仿函数(Functor):也称为函数对象(Function object),行为类似函数,可作为算法的某种策略。从实现角度来看,仿函数是一种重载了 operator() 的类或者模板类;
  • 适配器(Adaptor):一种用来修饰容器、仿函数或者迭代器接口的机制。例如 STL 提供的 queue 和 stack,就是一种空间配接器,因为它们的底部完全借助于 deque;
  • 分配器(allocator):也称为空间配置器,负责空间的配置与管理。从实现的角度来看,配置器是一个实现了动态配置空间、空间管理、空间释放的模板类。

2.2 容器

(1)序列式容器(Sequence containers)—— 每个元素都有固定位置,取决于插入时机和地点,和元素值无关,如 vector、deque、list 等;

  • Vector:将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速,但是在中部或头部安插元素比较费时;
  • Deque:是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速,但是在中部安插元素比较费时;
  • List:双向链表,不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针;

(2)关联式容器(Associated containers)—— 元素位置取决于特定的排序准则,和插入顺序无关,如 set、multiset、map、multimap 等。

  • Set / Multiset:内部的元素依据其值自动排序,set 内的相同数值的元素只能出现一次,multiset 内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
  • Map / Multimap:map 的元素是成对的键值 / 实值,内部的元素依据其值自动排序,map 内的相同数值的元素只能出现一次,multimap 内可包含多个数值相同的元素,内部由二叉树实现,便于查找;

注意:容器类自动申请和释放内存,无需 new 和 delete 操作。


2.3 算法

       算法部分主要由头文件 组成。

  • 是所有 STL 头文件中最大的一个,是由很多模板函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能有比较、交换、查找、遍历、复制、修改、移除、反转、排序、合并等操作;
  • 体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作;
  • 中则定义了一些模板类,用以声明函数对象。

       STL中算法大致分为四类:

  • 非可变序列算法:指不直接修改其所操作的容器内容的算法;
  • 可变序列算法:指可以修改它们所操作的容器内容的算法;
  • 排序算法:对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作;
  • 数值算法:对容器内容进行数值计算。

2.4 适配器

       “适配器是使一种事物的行为类似于另外一种事物行为的机制”,适配器对容器进行包装,使其表现出另外一种行为。例如 stack> 内部使用顺序容器 vector 来存储数据,但是表现出了栈的功能。STL 提供了三种顺序容器适配器:queue(FIFO队列)、priority_queue(优先级队列)和 stack(栈)。

  • 头文件
    #include     // stack
    #include     // queue、priority
种类 默认顺序容器 可用顺序容器 说明
stack deque vector、list、deque
queue deque list、deque 基础容器必须提供 push_front() 运算
priority_queue vector vector、deque 基础容器必须提供随机访问功能
  • 适配器的使用

2.4.1 stack

    stack s;  // 初始化
    stack> stk;  // 覆盖默认容器类型,使用vector实现stk
    s.empty();     // 判断stack是否为空,为空返回true,否则返回false
    s.size();      // 返回stack中元素的个数
    s.pop();       // 删除栈顶元素,但不返回其值
    s.top();       // 返回栈顶元素的值,但不删除此元素
    s.push(item);  // 在栈顶压入新元素item

2.4.2 queue & priority_queue

    // queue only:
    queue q;  // 初始化
    q.front();     // 返回队首元素的值,但不删除该元素
    q.back();      // 返回队尾元素的值,但不删除该元素
 
    // priority_queue only:
    priority_queue q;  // 初始化
    q.top();       // 返回具有最高优先级的元素值,但不删除该元素
    
    // both:
    q.empty();     // 判断队列是否为空
    q.size();      // 返回队列长度
    q.push(item);  /* 对于queue,在队尾压入一个新元素;
                    * 对于priority_queue,在基于优先级的适当位置插入新元素
                    */

三、STL 的使用场景

3.1 向量 vector

底层实现:动态数组

适用场景:需要快速查找,不需要频繁插入删除,如软件历史操作记录的存储。


3.2 双端队列 deque

底层实现:链表

使用场景:支持头端的快速移除,尾端的快速添加,如排队购票系统。如果采用 vector,则头端移除时,会移动大量的数据,速度慢。


3.3 vector 与 deque 的比较(数组和链表的特性区别)

  • vector.at() 比 deque.at() 效率高,如 vector.at(0) 是固定的,deque 的开始位置却不固定;
  • 如果有大量释放操作的话,vector 花费的时间更少,这与二者的内部实现有关;
  • deque 支持头部的快速插入与快速移除,这是 deque 的优势(链表)。

3.4 队列 list

底层实现:链表

使用场景:支持频繁的不确定位置元素的插入删除,不需要快速查找,如公交车乘客的存储。


3.5 集合 set

底层实现:红黑树(平衡二叉树)

使用场景:查找具体到某个单位,区别于 vector 一般是某个范围。需要元素有序,查找 / 删除 / 插入的性能相同,效率都是 O(logN)。如对游戏个人得分记录的存储,要求按从高到低的顺序排列。


3.6 映射 map

底层实现:红黑树

使用场景:查找具体到某个单位,区别于 set 范围更大,如按 ID 号存储十万个用户,想要快速通过 ID 查找对应的用户。


3.7 对 vector、set、map 的区分

  • 当班里有100个人,我们需要不断查看这100个人的数据,这时我们使用 vector 最好,这就是相对于某个范围。
  • 当班里仍有100个人,我们只需要查看某个人的数据,我们这时不使用 vector,而应该使用 set,这就是相对于具体某个人。
  • 当班里有10000个人时,我们仍只需要查看某个人的数据,我们这时不使用 set,而应该使用 map,因为范围扩大,用 map 效率更高。

四、常用容器用法介绍

将陆续更新各个容器的详细用法链接

【C++】STL - 向量 vector

【C++】STL - 集合 set

你可能感兴趣的:(【C++】STL,c++,数据结构)