STL c++11 容器存储结构总结

一则故事

有一天我准备集成一个同事的代码,在我简单测试的时候报错了

当我定位到代码位置时,发现他在访问list容器最后一个元素时,直接auto iter = list_.end();

当我去和他讨论这个问题时,我和他说,一般stl容器end()指的是容器最后一个元素的下一个位置。而他在网上找到的资料却是,end()指的是访问容器最后一个元素。之后他发现的原因是vscode自动帮他优化了。

这里我还是建议看看标准的文档

std::list<T,Allocator>::end, std::list<T,Allocator>::cend - cppreference.com

STL容器的逻辑设计上的结构与数学上的“前闭后开”区间是差不多的,

就比如想表示某容器有0,1,2,3,那么容器就得表示为[0,4),即0为begin(),4就是end(),因此,end()必须是指向容器实际最后一个元素的下一个位置

而每个容器都会“有头有尾”,即begin()和end(),均为迭代器(我们可以认为是个头指针和尾指针来表示区间的左右边)

为什么是“前闭后开”?如图对比可看出,

  1. “前闭后闭”的话,不管是空容器还是容器有单个元素时,需要增加额外的判断才能区分出来,容易存在边界问题
  2. “前闭后开”的话,只要这两个指针差1,就能表示有单个元素;这两个指针相等就能表示为空容器。

STL容器

我在听侯捷老师的课的时候总结了几个关于各大容器的底层结构:

顺序容器

顺序容器它并不是物理上的内存连续,而是逻辑上的连续,也就是我们可以根据容器中的位置来存放和访问元素,比如某容器A,我可以通过A[0]访问到第0位置的元素

其中顺序容器有array、vector、deque、list、forward-list ...

array --- 固定大小数组

顾名思义,它的大小是固定的

也就是,比如 std::array<int,3> a = {0,1,2}; 想让a插入一个4,是不可能的,它的大小只有3,仅能修改容器里面的元素值

vector---可变数组(向量)

与array相反,它的容量大小是可以变化的,比如我们通过push_back或emplace_back插入元素时,vector的size()增加!

注意,vector的实际空间大小capatity()会比size()大!

  • vector的扩充是2倍增长的,实际上的2倍增长是找更大的空间将原来容器里面的元素搬到过去,并非在模为扩充。
  • vector新增元素是将元素push到容器的尾部,但有个前提,vector有足够的空间push​​​​​​。
  • 假设一个房间可以装20个人,目前已经有20个人,准备插入一个人的时候,插不进了,这时候将这20个人移到可以装下40人的房间里面去,这样的话,之后很多次push的时候不需要去走申请内存的流程了。

deque---双端队列

两端都均可以扩充,均可以push

  • deque是分段连续的,由多个buffer组合而成,但逻辑上是整段连续的,即仍可以通过下标来访问元素
  • 它的扩充则就是可以在两端新增多个buffer
  • deque可以实现stack栈(“先进后出”),也可以实现queue(“先进先出”)

list---双向链表

动态分配内存

forward-list---单向链表

动态分配内存

关联容器

说到"关联"两个字,我们应该能联想到数据库,关联容器也相当于一个小型关联数据库,有唯一的key对应其value,因此,很便于查找

下面的容器,若只要带有multi,也就是key可以重复

有序容器(本质是红黑树)

有序指的是key是有顺序的,

set/multiset
  • key = value,比如 std::set<int> _s = {2,4,5};其中key=2的value=2
map/multimap
  • 其中multimap无法通过中括号来插入,比如std::multimap<int,int> _map = {{2,1},{2,3}},若我_map[2] = 4,你说我到底要改哪个key的值?

无序容器(本质是链式哈希表)

其中有unordered_set/unordered_multiset,unordered_map/unordered_multimap

哈希表中的篮子即bucket一定会比实际元素多,当元素个数大于等于篮子个数时,哈希表会扩充到原来的两倍,再对所有元素重新哈希

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值