STL 简介与总结

  STL (Standard Template Library) 标准模板库是 C++ 的内置库,提供了一系列常用的数据结构与算法,而且在使用的时候无需手动管理内存。这篇文章会先介绍 STL 的各个部件与设计思路,然后总结各种容器的基本性质和底层实现。

STL 简介

  STL 有六大组件:容器,算法,迭代器,仿函数,配接器,配置器。STL 的核心是泛型容器和算法,可以方便地储存和操作各种类型。STL 组件耦合度低,复用性高。

  1. 容器 (Container) : 常用的数据结构,如 vector, list, deque, set, map 等,用来存放数据。
  2. 算法 (Algorithm) : 常用的算法,如 sort, find, remove 等,支持各种容器类型。
  3. 迭代器 (Iterator) : 是一种“泛型指针”,可以在各种类型上做类指针的操作。
  4. 仿函数 (Functor) : 统一的可调用对象,可以传入泛型算法中作为策略使用。
  5. 配接器 (Adapter) : 用来修饰容器,使容器表现出另一种行为,例如 queue, stack, 底层实际是 deque。
  6. 配置器 (Allocator) : 负责空间配置与管理,自动管理容器所使用的空间。
STL 内存管理

  STL 对象的内存管理由 std::allocator 负责,会自动进行容器内对象构造前的内存申请与析构后的内存释放。STL 内存管理的思路如下:

  1. 考虑了多线程状态
  2. 内存不足时自动向 system heap 要空间
  3. 考虑了内存碎片问题

  其中,内存碎片是通过双层级配置器来解决的。如果申请的内存大于 128 字节,那么通过第一层配置器直接向系统申请。如果小于 128 字节,则交给第二级配置器。第二级配置器管理了一个 free-list,通过这个 free-list 管理了一个小区块内存池。

STL容器基本性质表

顺序容器及适配器

容器性质访问查找插入删除其他
vector可变数组随机访问O(1)O(n)O(n)尾部插入删除O(1)
string字符可变数组随机访问O(1)O(n)O(n)尾部插入删除O(1)
priority_queueO(logn)O(logn)O(nlogn)O(nlogn)排序队列
list双向链表双向顺序访问O(n)O(n)O(n)插入/删除比较灵活
forward_list单向链表单向顺序访问O(n)O(n)O(n)插入/删除灵活
deque双端队列随机访问O(1)O(n)O(n)头尾插入删除O(1)
queue单端队列随机访问O(1)O(n)O(n)尾部插入删除O(1)
stack随机访问O(1)O(n)O(n)
array固定大小数组随机访问O(1)--不能插入/删除

关联容器

容器性质访问查找插入删除其他
map有序字典O(logn)O(logn)O(logn)O(logn)
set有序集合O(logn)O(logn)O(logn)O(logn)
multimap有序字典O(logn)O(logn)O(logn)O(logn)可重复
multiset有序集合O(logn)O(logn)O(logn)O(logn)可重复
unordered_map无序字典O(1)O(1)O(1)O(1)
unordered_set无序集合O(1)O(1)O(1)O(1)
unordered_multimap无序字典O(1)O(1)O(1)O(1)可重复
unordered_multiset无序集合O(1)O(1)O(1)O(1)可重复

STL容器介绍

连续内存顺序容器
vector

  vector是可变大小的数组,允许插入和删除,是在 C++ 里经常用来代替 C 数组的一种容器,支持快速随机访问。

  vector 自行维护了一段内存,当插入时内存不够时,会重新申请一段更大的内存,并把目前的数据移动到新内存里,再进行插入。不同编译器的扩容倍数不一样,有 1.5 倍或 2 倍的,1.5倍造成的内存碎片更少。

string

  string 的底层就是 vector<char>,但 string 本身还提供了许多字符串操作函数,比如append, substr, replace, find, compare, to_string, stoi等。

priority_queue

  priority_queue 是优先队列,放入其中的元素会自动排序,一般都是做最大堆/最小堆使用的,STL 提供了 push, pop, top 三种基本操作。

  priority_queue 是一种适配器,是对 vector 容器的再封装。priority_queue 以 vector 为底层容器,使用堆 heap 作为处理规则。

半连续内存顺序容器
deque

  deque 是双端队列,可以从首尾快速增删,也支持用下标随机访问元素,并不是完全封装的队列,提供了很大的方便。

  deque 的底层是一小块连续空间,该空间每个元素都是指向另一段连续内存的指针,相当于 deque 管理的是一段内存映射表。所以,访问 deque 的元素需要经过两次查找,访问速度要比vector慢。

stack & queue

  stack 是栈,queue 是单端队列。

  stack 和 queue 都是适配器,它们的底层一般是 deque。不用 vector 作为底层的原因可能是因为扩容比较耗时。

非连续内存顺序容器
list & forward_list

  list 是双向链表,forward_list 是单向链表,两者的底层也是链表,可以快速增删。

  list 的插入,删除,迭代器都和连续内存容器不一样,lst.before_begin(), lst.insert_after(), lst.erase_after()。另外,<algorithm> 的泛型算法对 list 不适用。list 有专用版本,例如:lst.merge, lst.sort, lst.remove, lst.reverse,lst.unique, lst.splice 等。

有序关联容器
set

   set 是集合,有序排列,默认从小到大,不允许重复的关键字。不允许用下标访问,只能用迭代器直接访问元素。

  multiset 是允许重复关键字的 set。STL 还为 set 提供了一些集合运算的函数,如交集set_intersection、并集set_union、差集set_difference等。

map

  map 是字典,存储的为 {key, value} 对,可以通过关键字来查找值。map 可以通过下标运算符来建立元素,例如 m[3]++;,若之前不存在 key 为 3 的元素,则这条语句会直接创建 key 为 3 的元素,再自增其 value。

  有序关联容器都具有equal_range, lower_bound, upper_bound, merge, count 等自带算法。

红黑树

  有序关联容器的内部结构都是红黑树 (Red Black Tree, RB-tree)。

  红黑树是一种二叉查找树,也是一种平衡二叉树。红黑是可以用 O(logn) 的时间复杂度进行查找,插入,删除操作。红黑树是统计性能较高的平衡二叉树,被广泛应用于存储有序数据的场景。

  红黑树的平衡并不严格,其只要求树的最长路径不大于两倍最短路径的长度,但这也比 BST 好很多,可以保证 O(logn) 的复杂度,不会像 BST 可能退化到 O(n)。

  红黑树的不平衡在 3 次旋转之内就可以回归平衡,这让它的统计性能比 AVL 树更高。

红黑树与哈希表对比
  1. 红黑树有序,hash 表无序
  2. hash 表查找速度比红黑树快,复杂度为是 O(1) ,但 hash 表会在 hash 函数上消耗时间,数据量小时,hash 表不一定比红黑树快。而当 hash 表的数据量极大时,可能会因为 hash 函数的质量导致插入/查找元素的时间低于红黑树。
  3. hash 表可能会消耗多余的内存,而红黑树不会。
  4. 如果数据是静态的,可以使用红黑树,如果数据是动态的,红黑树具有更好的统计性能。
无序关联容器

  无序关联容器有四种,unordered_set,unordered_map,unordered_multiset,unordered_multimap。

  无序容器的底层是哈希表,STL 的哈希表是由 vector 和 list 组成的。当空间不够的时候会倍增,表中所有数据在倍增后会重新 hash。STL 也允许自行传入 hash 函数和重组存储。

应用场合

  • 不增删,静态存储,C 数组或者 array(STL 的静态数组)
  • 需要动态增长,vector
  • 增删大部分在头尾,deque
  • 有大量增删,list
  • 其他的容器比较有特点,按需使用
迭代器失效
  • vector, string
    • 插入时,如果存储空间重新分配,可能都失效,若没有重新分配,则插入之后迭代器,指针,引用可能失效。
    • 删除时,删除位置之后的迭代器,指针,引用都失效。
  • deque
    • 在首尾插入/删除,迭代器失效,但引用,指针不失效。
    • 在其他位置插入,迭代器,指针,引用都可能失效
    • 在其他位置删除,其他迭代器,引用,指针代都失效
  • list, forward_list
    • 插入删除后迭代器,指针,引用仍然有效 (删除的那一个失效)

使用迭代器的策略:

  • 最好每次增删或容量调整后重新定位现有迭代器
  • 不要保存 end() 返回的迭代器,若元素有增删,每次都要调用 end() 进行判断
  • 循环内使用 insert,erase 时要算清楚循环迭代器的位置,以及不同情况下是否该自增/自减

返回目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值