C++复习之(STL)
vector
1. 底层实现
Vector在堆中分配一段连续的内存空间来存放元素,是顺序容器。
共有三个迭代器,first:第一个元素开头位置; last:最后一个对象末尾位置;end:整个容器所占内存的末尾。因此可以通过迭代器运算来计算容器的对应空间。
2. 扩容
如果集合已满,在新增数据的时候,就要分配⼀块更⼤的内存,将原来的数据复制过来,释放之前的内存,在插⼊ 新增的元素 所以对vector的任何操作,⼀旦引起空间᯿新配置,指向原vector的所有迭代器就都失效了。
size()返回当前元素的个数;capacity()当前容器容量。当capacity() == size()是,容器扩容。
两种扩容方式:固定扩容和翻倍扩容,前一个空间优先,后一个时间优先。
resize() 改变当前元素的数量,如果resize值小于当前的size,那么会将后面的元素舍弃。
reserve()改变当前容器的容量大小,如果reserve(len)的值 > 当前的capacity(),那么会᯿新分配⼀块能存len个对象的空间,然后把之前的对象通 过copy construtor复制过来,销毁之前的内存;当reserve(len)中len<=当前的capacity(),则数组中的capacity不变,size不变,即不对容器做任何改变。
3. 成员函数
push_back() emplace_back(),插入一个元素,先判断内存是否足够,如果足够直接插入,不够先进行扩容再插入。
pop_back(),移出最后一个元素。
erase(),移出一个或一段元素。
swap(),交换两个vector的size,capacity,用于内存缩减,在一定程度上可以代替clear()和shrank_to_fit()函数。
List
1. 底层实现
双向链表。
2. 成员函数
emplace_front()、emplace_back() :在头或尾部生成元素
pop_front()、pop_back() :头或尾部删除元素
empalce() :插入元素
erase() :删除元素
splice() : 将一个 list 容器中的元素插入到另一个容器的指定位置。
remove_if() : 删除容器中满足条件的元素。
unique():删除容器中相邻的重复元素,只保留一个。
merge() : 合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。
sort():通过更改容器中元素的位置,将它们进行排序。
reverse():反转容器中元素的顺序。
deque
讲得较好博客:C++复习篇(9)-详解deque、stack、queue的实现原理 (qq.com)
1. 底层实现
是一个双端数组,使用上看起来是连续的,但在物理层面是由多段连续空间缓冲区组成,并用一个map(与STL的map不是同一个东西)存储每个缓冲区的首地址。因此相对于vector来讲,deque在首端也可以以O(1)的复杂度增删元素,但是由于其查找元素中间过程更多,效率是低于vector的。
除了维护map,还维护一个start和finish迭代器,由四部分组成,第一个缓冲区首元素地址,最后元素地址,当前存储位置地址,起始结点;最后一个缓冲区首元素地址,最后元素地址,当前存储位置地址,末尾结点。
2. 扩容方式
在尾部插入元素,如果需要申请新的缓冲区,改变finish迭代器;
在头部插入元素,如果需要申请新的缓冲区,改变start迭代器;
map内存不够,则扩容方式和vector类似。
stack 和 queue
1. 底层实现
stack 和 queue底层实现是利用deque,是配接器。
stack 先入后出,无法遍历,没有迭代器;queue 先入先出,无法遍历,无迭代器。
map、unordered_map 和 set、unordered_set
1. 底层实现
map和multi_map的底层实现是红黑树,内部元素排列是有序的;
unordered_map底层实现是哈希表(实现方式是vector+链表),元素的排列顺序是杂乱⽆序的。哈希表中的vector是以质数设计表格大小扩容的,使用质数可以有效减少哈希冲突。哈希表的大小取决于一组质数,原因是在hash函数中,你要用这些质数来做模运算(%)。而分析发现,如果不是用质数来做模运算的话,很多生活中的数据分布会集中在某些点上,会出现哈希冲突。所以为了减少哈希冲突而采用了质数做模的除数。且迭代器只能向前不能后退。使用链地址法解决哈希冲突。
map和set的区别在于map有是键值对,相当于字典,把⼀个值映射成另⼀个值;set只有键,⽤来判断某⼀个元素是不是在⼀个组⾥⾯。
STL的内存优化
二级分配机制 第一级,大于128bytes时,直接调用malloc申请内存; 第二级,小于128bytes时,维护一个大小为16的链表数组组成的内存池,内存大小分别为8、16....128bytes。根据输入大小,向上取8的整数倍,在相应链表元素中寻找,若元素为空(说明被占用),则调用refill函数,申请最多20个内存块。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)