C++ STL学习笔记(5) Vector容器, array容器,deque容器
动态增长的数组vector,当它放入的元素满了的时候,会自动的扩充内存,但是,在计算机中内存不能够实现原地扩充,因为在申请了一块固定大小的内存之后,这块内存不管有没有用完,他后面的内存都有可能别的内容被占用。所以扩充的过程是在内存中别的地方找到一块足够大的内存,把原来的东西搬过去。
vector的内部示意图:
vector关键部分的实现代码: finish指向的是最后一个元素的后一个位置
可以先看一下vector定义的插入元素的方法,因为内存的扩容是发生在插入元素而内存不足的时候:
可以看到,在插入元素的时候,如果内存不足,会调用insert_aux的函数:
可以看到,insert_aux函数会开始的时候检查是否空间可用(很奇怪为什么到这里了还要检查空间是否够用,如果够用,则将元素继续插入到容器中,否则再次重新扩充内存,实际上,insert_aux函数不是是在这里被调用,它在其他地方也被调用,作为插入元素的函数,所以就会在刚开始的时候检查内存时候够用,这主要是针对别的地方调用它插入元素的时候使用的),可以看到,具体的内存扩充的代码在else语句里面,具体的实现如下所示:
所以在使用vector的时候,应该考虑到,在每次扩充内存的时候,会涉及到大量元素的拷贝动作,此时会调用拷贝构造函数,当拷贝完成后,释放掉原来的内存,需要同样调用析构函数,这是非常损耗性能的。
Vector的迭代器:
vector中迭代器的设计如下:
vector中迭代器的实现与前面讲的基本一样,也需要满足Iterator的一些基本的特征。
Array容器:
array本身就是C++种的数组,将它包装成容器,它就可以C++种容器的规律,比如可以提供迭代器,以便于让算法进行相应的操作,如果不将它数据进行这样的包装,数组就会被摈弃在STL的六大部件之外,失去了和这些部件之间的联系。
array的具体实现:
dequeue容器:
双向队列,内部的结构:
deque采用分段的方式(buffer),map指向的元素是一个指针,而这个指针指向的是buffer,所以map是一个只想指针的指针,存储map所指向的元素的容器是一个vector,。每一段buffer的元素满了的时候,deque会继续申请一块同样大小的内存,然后将内存的指针向前或者向后放入到map中,从而实现deque向前或者向后扩充。
deque的迭代器:
deque的迭代器有四个元素,cur, first,last, node, first指向内存段buffer的起始位置,last指向内存段buffer中最后一个元素的后一个位置(超尾),cur指向当前的元素,node指向当前buffer的指针, 也就是说指向vector中对应的指针。
可以看到dequeue的定义如下所示:
deque类中的定义的成员,可以看到map的类型,确实是指向指针的指针,还有迭代器start, finish.,以及对应的begin(),end()方法。
下面可以看一下迭代器的具体实现,有助于理解上面的原理图:
可以看到迭代其中的四个元素,node的类型也可以知道,即node是指向指针的。
deque<T>::insert( )方法:
在deque中插入元素,deque会智能的通过插入的元素的位置而决定调用的方法:如果靠近头部,则会将插入元素到头部,如果靠近尾部,则会将元素插入尾部,否则,会采取另一种插入方法。
deque如何模拟连续空间:通过 deque iterator实现,可以看到deque内部定义的方法:
可以看到,size方法中,出现了两个迭代器相减,所以这个减法是一个重载的运算符,两个迭代器相减,返回荣光期内元素的个数,所以减号运算符的重载方法是:finish-start是map中元素的个数,而每个map中元素指向的buffer中有固定个数的元素(buffer size),所以可以根据这些值计算出容器中元素的个数。它的具体的实现如下所示:
其中,node是map种元素的指针(map种元素的内存是连续的)。所以(node - x.node - 1)就是map_size.
cur-first是当前迭代器种多出来的元素(没有放满一个buffer)
x.last-x.cur是另一个参与运算的迭代器中多出来的元素(没有放满一个buffer)
迭代器中++,--的实现:
// 前缀加
self& operator++()
{++cur; // 切换到下一个元素if (cur == last) // 当前的buffer已经放满了{set_node(node + 1); // 跳到下一个node 节点 map中的下一个元素}return *this;
}// 后缀加
self& operator++(int dummy)
{self tmp = *this;++*this; // 在后缀加中调用前缀加return tmp;
}
还有其他一些方法的实现,+=,-=等运算符的重载,
例如,在重载迭代器的+=运算符的时候,需要考虑到,每次加了之后,是否会超出当前的buffer,如果从超出,就需要切换到下一个node,具体的实现思路如下所示:
deque容器其他方法的实现也与此类似,都与要考虑到节点的切换问题:
容器,queue, stack
从上图可以看出queue,stack和deque的关系,在实现queue,stack的时候,不需要再重写一个queue和stack,我们只需让他们内含一个deque,然后再禁止deque中的某些方法即可,实现方法如下所示:
stack的实现:
-------------------------------------------------------end---------------------------------------------------------
C++ STL学习笔记(5) Vector容器, array容器,deque容器相关推荐
- SGI STL 学习笔记二 vector
sequence containers Array Vector Heap Priority_queue List sList(not in standard) Deque Stack Queue S ...
- C++ STL学习笔记
C++ STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C ...
- 【C++ STL学习笔记】C++ STL序列式容器(array,vector,deque,list)
文章目录 C++ STL容器是什么? 迭代器是什么,C++ STL迭代器(iterator)用法详解 迭代器类别 迭代器的定义方式 C++序列式容器(STL序列式容器)是什么 容器中常见的函数成员 C ...
- C++STL学习笔记(4) 分配器(Allocator)
在前面的博客<C++ STL学习笔记(3) 分配器Allocator,OOP, GP简单介绍>中,简单的介绍了分配器再STL的容器中所担当的角色,这一节对STL六大部件之一的分配器进行详细 ...
- C++ STL学习笔记(3) 分配器Allocator,OOP, GP简单介绍
继续学习侯捷老师的课程! 在前面的博客<C++ STL学习笔记(2) 容器结构与分类>中介绍了STL中常用到的容器以及他们的使用方法,在我们使用容器的时候,背后需要一个东西支持对内存的使用 ...
- 菜鸟学习笔记:Java提升篇4(容器4——Collections工具类、其他容器)
菜鸟学习笔记:Java容器4--Collections工具类.其他容器 Collections工具类 容器其他知识点 队列Queue Enumeration接口 Hashtable Propertie ...
- 菜鸟学习笔记:Java提升篇3(容器3——泛型、排序)
菜鸟学习笔记:Java容器3--泛型.排序 泛型 泛型类 泛型接口 泛型方法 泛型继承 通配符"?" 泛型知识点补充 容器排序 Comparable接口与compareTo方法 C ...
- 菜鸟学习笔记:Java提升篇2(容器2——Map、Set、迭代器)
菜鸟学习笔记:Java容器2--Map.Set.迭代器 Map容器 HashMap的使用 Hash表讲解 Map实现 Set容器 HashSet的使用 实现 Iterator迭代器 Map容器 Has ...
- 菜鸟学习笔记:Java提升篇1(容器1——List)
菜鸟学习笔记:Java容器1--List容器 容器基本概念 List容器 ArrayList 初始化 add方法 remove方法 LinkList 链表 双向链表 初始化 add方法 remove方 ...
最新文章
- 干货丨入门机器学习,从搞懂这8大经典算法开始
- 制作嵌入式根文件系统(常见问题详解)
- 那些年的那些事CISC和RISC发展中的纠缠
- SQL Server 备份与恢复之八:还原数据库
- tomcat出现5个using_下肢深静脉血栓要警惕,出现这5个症状,马上看医生
- php网站接入微信支付,PHP接入微信H5支付的方法示例
- Ubuntu源码安装php-7.2.23
- Git/Github + TortoiseGit 使用教程
- VM10虚拟机安装图解
- linux 终端使用aplay播放wav
- 简单正则^(?![^a-zA-Z]+$)(?!\D+$)[0-9a-zA-Z]{6,35}$
- android转发短信到邮箱,利用短信通知的方式在Tasker中实现收到Android手机短信自动转发到邮箱...
- 使用python切割图片
- 百度糯米猴年初一夺冠 协同创新三大法器赢得漂亮
- 【转】固态硬盘恢复之30分钟大法操作技巧
- 联想电脑拯救者y7000触摸屏失灵的修复方法
- Ubuntu18如何下载微信和qq
- Flutter 功能最全的JsonToDart工具
- 香港理工大学智能计算实验室招收PhD/博士后/研究助理
- 正则表达式的字符串匹配
热门文章
- k8s核心技术-集群安全机制(RBAC实现鉴权)---K8S_Google工作笔记0040
- Netty工作笔记0046---TaskQueue自定义任务
- STM32工作笔记0029---认识电路原理图中的VCC,VDD,VEE,VSS
- C++容器删除数据时迭代器失效
- 根据sessionId获取Session对象
- 2017年(毕业生)暑期实习信息汇总
- boost学习之BOOST_FOREACH
- 随想录(文件系统的第一个用户程序shell)
- 计算机休眠状态播放音乐,win7系统休眠后不能播放音乐怎么解决
- python列表迭代器_python迭代器生成器-迭代器和list区别