C++STL学习第一讲(从体系结构角度讲解STL)

第一讲 从体系结构角度讲解STL

1. C++ Standard Library vs Standard Template Library

  • C++中的STL实现了数据结构和算法的分离,被包括在C++标准库(C++ Standard Library)中;
  • C++ Standard Library > STL(六大部件);
    在这里插入图片描述

2. STL体系结构基础介绍

1. STL六大组件
  • 容器(Container):一些封装的数据结构,例如list、deques、vector、front list等;
  • 迭代器(Iterator):为访问容器中的数据而写的一些方法;
  • 算法(Algorithm):为处理容器中的数据而写的一些方法;
  • 仿函数(Functor):实现了函数功能的类。(本质是一个类,里面只实现算法(函数)功能,调用时看着像使用函数,但使用的是类创建对象里面的方法);
  • 适配器(Adaptor):类和类之间转换、合作时,由于代码不兼容,因此需要另一些类代码完成中间转换、合作的“手续”事宜。这些因为克服STL中类代码合作、转换的代码封装称为适配器;
  • 分配器(Allocator):给数据分配内存一些代码。
2. STL组件关系
  • STL把数据结构和算法划分开,这不符合**面向对象OO(Object-Oriented)**编程思路;
  • 容器(Container) == 数据结构;
    • 为用户隐藏了内存的相关内容;
  • 分配器(Allocator)负责内存的相关工作;
  • 迭代器(Iterator)作为容器和算法之间联系的桥梁,是泛型类型的指针;
    在这里插入图片描述
3. 组件使用示例
  • 14行的not1和bind2nd是函数的adapter适配器;
  • 13行的代码表示:找到容器中 >= 40 的元素个数;
    在这里插入图片描述
4. 常见时间复杂度

在这里插入图片描述

5. STL所有容器头尾的指向遵循左闭右开原则
  • 尾部迭代器指向容器最后一个元素的下一个位置(不属于容器);
    在这里插入图片描述
6. 遍历容器方法
  • 常规索引遍历for;
  • 迭代器遍历;
  • 基于范围的for循环(range-based for statement)

3. 容器结构与分类

1. Containers分类
  • Sequence Containers(序列式容器):

    • Array(数组,C++11):

      • 大小固定,连续空间;不能进行增加和删除;
      • 理解为内置数组的升级版;
    • Vector:

      • 连续空间,可以在尾部扩展【push_back(…)(在头部扩展耗费时间,需要全部数据移动)】;
      • 每次空间不足时,都会把可用空间扩充两倍;容易造成空间浪费;
      • 扩容过程:
        • 找到另一块连续的空间,将原来的数据转移过去,过程缓慢;
    • Deque(双端队列):

      • (让用户以为整体是)连续空间,可以在两端扩展【push_front(…)和push_back(…)】;
      • Deque其实是分段连续(并不是整体连续),如图;
        • Deque维护一个连续指针空间map,每个指针指向一段连续的等量空间buffer;
        • 【但Deque会制造假象,让用户误以为是整体连续的;】
      • 扩容过程:
        • 每次扩充一个buffer;
        • 当push_back(…)空间不足时,在指针数组尾部新增一个指针,指向新的buffer;
        • 当push_front(…)空间不足时,在指针数组头部新增一个指针,指向新的buffer;
          在这里插入图片描述
    • List(双向链表):

      • 离散空间,可以在两端扩展【push_front(…)和push_back(…)】;
      • 扩容过程:
        • 每次扩充一个;
    • Forward-List(单向链表,C++11):

      • 离散空间,在头部扩展【push_front(…)(在尾部扩展太耗费时间)】;
      • 扩容过程:
        • 每次扩充一个;
          在这里插入图片描述
  • Associative Containers(关联式容器):

    • key有序:

      • Set / Multiset【理解成key就是value,value就是key】:
        • Set(key不能重复);
        • Multiset(key可以有重复);
      • Map / Multimap:
        • Map(key不能重复);
        • Multimap(key可以有重复);
      • 底层实现结构都是红黑树
    • key无序(C++11):

      • Unordered Set / Multiset:
      • Unordered Map / Multimap:
      • 底层实现结构都是 Separate Chaining(拉链法)的HashTable
  • 扩容过程:
    + 当元素的个数 >= bucket(篮子)的个数:
    + 开始以8倍进行扩容;
    + 当bucket数量 >= 512,每次扩容两倍;
    + 每次扩容所有元素需要重新计算;
    在这里插入图片描述

2. 特殊的容器stack、queue
  • stack、queue其实不是容器,而是容器适配器
  • 它们的缺省底层结构是Deque;
  • 因为stack、queue有特殊的结构性质,所以stack、queue没有迭代器:
    • 如果有提供迭代器,用户可能使用迭代器,进行修改数据、删除数据,这会破坏stack、queue的特殊结构;
3. Sequence Containers的使用
  • 使用插入、排序、查找、查看首尾;

  • clock()函数:返回程序开始到执行这个函数的时间,单位毫秒;

  • array的简单使用

    • 不能插入、删除;
    • 赋值:c[i] = value;
    • 属性:【以下函数后面重复不再说明】
      • size()函数:获取目前存在的元素数;
      • 获取首尾:front()、back();
      • data()函数:返回容器的起始地址;
        在这里插入图片描述
  • vector的简单使用

    • 插入:push_back(…);
    • 属性:
      • capacity()函数:返回vector能存储数据的个数;
      • 【每次空间不足时,进行两倍扩展】
        在这里插入图片描述
  • list的简单使用

    • 插入:push_back(…)和push_front(…);
    • 属性:
      • max_size()函数:返回允许的最大存储数据的个数【后面不再重复说明】;
    • 排序:
      • 注意197行,有自定义的sort(…);
      • 有一些容器会自定义sort(…),优先使用容器自定义的sort(…)函数;
        在这里插入图片描述
  • forward_list简单使用

    • 插入:
      • push_front(…);
      • Forward-List没有push_back(…)函数,这样插入速度太慢,只有push_front(…),和vector没有push_front(…)函数的道理一样;
    • 属性:没有back()函数;
    • 排序:有自定义sort(…)函数;
      在这里插入图片描述
  • deque简单使用

    • 插入:push_back(…)和push_front(…);
      在这里插入图片描述
4. Associative Containers的使用
  • mulitset的简单使用:

    • 插入:insert(…);
    • 删除:erase(…);
    • 查找:有自定义的find(…)函数
      在这里插入图片描述
  • mulitmap的简单使用:

    • 插入:insert(pair<…, …>(…, …));
    • 删除:erase(…);
    • 查找:有自定义的find(…)函数
      在这里插入图片描述
  • unordered_multiset的简单使用:

    • 插入:insert(…);
    • 删除:erase(…);
    • 查找:有自定义的find(…)函数
    • 属性:
      • bucket_count():返回篮子的个数;
        • bucket的数量一定 > 元素的数量;
      • load_factor():计算载重因子;
      • max_bucket_count():最大的篮子个数;
      • max_load_factor():最大的载重因子;
        在这里插入图片描述
        在这里插入图片描述
  • unordered_multimap的简单使用:

    • 插入:insert(pair<…, …>(…, …));
    • 删除:erase(…);
    • 查找:有自定义的find(…)函数
      在这里插入图片描述
  • 【key值不能重复】的容器使用:

    • 插入、删除、查找操作和multi的差不多;区别在于key值不能重复;
    • set;
    • map;
    • unordered_set;
    • unordered_map;

4. allocator分配器

1. STL容器的默认分配器
  • STL容器的默认分配器 == std::allocator;
  • 容器的构造函数:
    在这里插入图片描述
2. 其他分配器
  • 其他分配器都是非标准库的内容,是额外扩充的,从include的头文件可以看出(不是标准库的形式);
  • 其他分配器的头文件、namespace以及使用如下图所示;
    • 以list为例,在构造函数使用不同的分配器;
      在这里插入图片描述
3. 直接使用分配器
  • 分配器作为一个class,【虽然可以直接使用它,但没有这个必要,建议直接使用容器】;
  • 下图简单示范如何直接使用分配器:
    • 分配和释放都需要指定大小;
      在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值