当前位置: 首页 > 编程日记 > 正文

c++ STL容器初探

什么是容器

首先,我们必须理解一下什么是容器,在C++ 中容器被定义为:在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器。很简单,容器就是保存其它对象的对象,当然这是一个朴素的理解,这种“对象”还包含了一系列处理“其它对象”的方法,因为这些方法在程序的设计上会经常被用到,所以容器也体现了一个好处,就是“容器类是一种对特定代码重用问题的良好的解决方案”。

容器还有另一个特点是容器可以自行扩展。在解决问题时我们常常不知道我们需要存储多少个对象,也就是说我们不知道应该创建多大的内存空间来保存我们的对象。显然,数组在这一方面也力不从心。容器的优势就在这里,它不需要你预先告诉它你要存储多少对象,只要你创建一个容器对象,并合理的调用它所提供的方法,所有的处理细节将由容器来自身完成。它可以为你申请内存或释放内存,并且用最优的算法来执行您的命令。

容器是随着面向对象语言的诞生而提出的,容器类在面向对象语言中特别重要,甚至它被认为是早期面向对象语言的基础。在现在几乎所有的面向对象的语言中也都伴随着一个容器集,在C++ 中,就是标准模板库(STL )。

和其它语言不一样,C++ 中处理容器是采用基于模板的方式。标准C++ 库中的容器提供了多种数据结构,这些数据结构可以与标准算法一起很好的工作,这为我们的软件开发提供了良好的支持!

通用容器的分类

STL 对定义的通用容器分三类:顺序性容器、关联式容器和容器适配器

顺序性容器 是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序性容器中的每个元素均有固定的位置,除非用删除或插入的操作改变这个位置。这个位置和元素本身无关,而和操作的时间和地点有关,顺序性容器不会根据元素的特点排序而是直接保存了元素操作时的逻辑顺序。比如我们一次性对一个顺序性容器追加三个元素,这三个元素在容器中的相对位置和追加时的逻辑次序是一致的。

关联式容器 和顺序性容器不一样,关联式容器是非线性的树结构,更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。但是关联式容器提供了另一种根据元素特点排序的功能,这样迭代器就能根据元素的特点“顺序地”获取元素。

关联式容器另一个显著的特点是它是以键值的方式来保存数据,就是说它能把关键字和值关联起来保存,而顺序性容器只能保存一种(可以认为它只保存关键字,也可以认为它只保存值)。这在下面具体的容器类中可以说明这一点。

容器适配器 是一个比较抽象的概念, C++的解释是:适配器是使一事物的行为类似于另一事物的行为的一种机制容器适配器是让一种已存在的容器类型采用另一种不同的抽象类型的工作方式来实现的一种机制。其实仅是发生了接口转换。那么你可以把它理解为容器的容器,它实质还是一个容器,只是他不依赖于具体的标准容器类型,可以理解是容器的模版。或者把它理解为容器的接口,而适配器具体采用哪种容器类型去实现,在定义适配器的时候可以由你决定

下表列出STL 定义的三类容器所包含的具体容器类:

标准容器类

特点

顺序性容器

vector

从后面快速的插入与删除,直接访问任何元素

deque

从前面或后面快速的插入与删除,直接访问任何元素

list

双链表,从任何地方快速插入与删除

关联容器

set

快速查找,不允许重复值

multiset

快速查找,允许重复值

map

一对多映射,基于关键字快速查找,不允许重复值

multimap

一对多映射,基于关键字快速查找,允许重复值

容器适配器

stack

后进先出

queue

先进先出

priority_queue

最高优先级元素总是第一个出列

vector ,deque 和 list

顺序性容器

向量 vector :  

是一个线性顺序结构。相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,由于它的特性我们完全可以将vector 看作动态数组。
在创建一个vector 后,它会自动在内存中分配一块连续的内存空间进行数据存储,初始的空间大小可以预先指定也可以由vector 默认指定,这个大小即capacity ()函数的返回值。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,在重新分配空间时它会做这样的动作:

首先,vector 会申请一块更大的内存块;

然后,将原来的数据拷贝到新的内存块中;

其次,销毁掉原内存块中的对象(调用对象的析构函数);

最后,将原来的内存空间释放掉。

如果vector 保存的数据量很大时,这样的操作一定会导致糟糕的性能(这也是vector 被设计成比较容易拷贝的值类型的原因)。所以说vector 不是在什么情况下性能都好,只有在预先知道它大小的情况下vector 的性能才是最优的。

vector 的特点:
(1) 指定一块如同数组一样的连续存储,但空间可以动态扩展。即它可以像数组一样操作,并且可以进行动态操作。通常体现在push_back() pop_back() 。
(2) 随机访问方便,它像数组一样被访问,即支持[ ] 操作符和vector.at()
(3) 节省空间,因为它是连续存储,在存储数据的区域都是没有被浪费的,但是要明确一点vector 大多情况下并不是满存的,在未存储的区域实际是浪费的。

(4) 在内部进行插入、删除操作效率非常低,这样的操作基本上是被禁止的。Vector 被设计成只能在后端进行追加和删除操作,其原因是vector 内部的实现是按照顺序表的原理。
(5) 只能在vector 的最后进行push 和pop ,不能在vector 的头进行push 和pop 。
(6) 当动态添加的数据超过vector 默认分配的大小时要进行内存的重新分配、拷贝与释放,这个操作非常消耗性能。 所以要vector 达到最优的性能,最好在创建vector 时就指定其空间大小。

双向链表list

是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。

由于其结构的原因,list 随机检索的性能非常的不好,因为它不像vector 那样直接找到元素的地址,而是要从头一个一个的顺序查找,这样目标元素越靠后,它的检索时间就越长。检索时间与目标元素的位置成正比。

虽然随机检索的速度不够快,但是它可以迅速地在任何节点进行插入和删除操作。因为list 的每个节点保存着它在链表中的位置,插入或删除一个元素仅对最多三个元素有所影响,不像vector 会对操作点之后的所有元素的存储地址都有所影响,这一点是vector 不可比拟的。

list 的特点:
(1) 不使用连续的内存空间这样可以随意地进行动态操作;
(2) 可以在内部任何位置快速地插入或删除,当然也可以在两端进行push 和pop 。
(3) 不能进行内部的随机访问,即不支持[ ] 操作符和vector.at() ;
(4) 相对于verctor 占用更多的内存。

双端队列deque

是一种优化了的、对序列两端元素进行添加和删除操作的基本序列容器。它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小。它不需要重新分配空间,所以向末端增加元素比vector 更有效。

实际上,deque 是对vector 和list 优缺点的结合,它是处于两者之间的一种容器。

deque 的特点:
(1) 随机访问方便,即支持[ ] 操作符和vector.at() ,但性能没有vector 好;
(2) 可以在内部进行插入和删除操作,但性能不及list ;
(3) 可以在两端进行push 、pop ;

三者的比较

下图描述了vector 、list 、deque 在内存结构上的特点:

vector 是一段连续的内存块,而deque 是多个连续的内存块, list 是所有数据元素分开保存,可以是任何两个元素没有连续。

vector 的查询性能最好,并且在末端增加数据也很好,除非它重新申请内存段;适合高效地随机存储。

list 是一个链表,任何一个元素都可以是不连续的,但它都有两个指向上一元素和下一元素的指针。所以它对插入、删除元素性能是最好的,而查询性能非常差;适合 大量地插入和删除操作而不关心随机存取的需求。

deque 是介于两者之间,它兼顾了数组和链表的优点,它是分块的链表和多个数组的联合。所以它有被list 好的查询性能,有被vector 好的插入、删除性能。 如果你需要随即存取又关心两端数据的插入和删除,那么deque 是最佳之选。

关联容器

set, multiset, map, multimap 是一种非线性的树结构,具体的说采用的是一种比较高效的特殊的平衡检索二叉树—— 红黑树结构。(至于什么是红黑树,我也不太理解,只能理解到它是一种二叉树结构)

因为关联容器的这四种容器类都使用同一原理,所以他们核心的算法是一致的,但是它们在应用上又有一些差别,先描述一下它们之间的差别。

set,又称集合,实际上就是一组元素的集合,但其中所包含的元素的值是唯一的,且是按一定顺序排列的,集合中的每个元素被称作集合中的实例。因为其内部是通过链表的方式来组织,所以在插入的时候比vector 快,但在查找和末尾添加上被vector 慢。

multiset ,是多重集合,其实现方式和set 是相似的,只是它不要求集合中的元素是唯一的,也就是说集合中的同一个元素可以出现多次

map,提供一种“键- 值”关系的一对一的数据存储能力。其“键”在容器中不可重复,且按一定顺序排列(其实我们可以将set 也看成是一种键- 值关系的存储,只是它只有键没有值。它是map 的一种特殊形式)。由于其是按链表的方式存储,它也继承了链表的优缺点。

multimap , 和map 的原理基本相似,它允许“键”在容器中可以不唯一

关联容器的特点是明显的,相对于顺序容器,有以下几个主要特点:

1, 其内部实现是采用非线性的二叉树结构,具体的说是红黑树的结构原理实现的;

2, set 和map 保证了元素的唯一性,mulset 和mulmap 扩展了这一属性,可以允许元素不唯一;

3, 元素是有序的集合,默认在插入的时候按升序排列。

基于以上特点,

1, 关联容器对元素的插入和删除操作比vector 要快,因为vector 是顺序存储,而关联容器是链式存储;比list 要慢,是因为即使它们同是链式结构,但list 是线性的,而关联容器是二叉树结构,其改变一个元素涉及到其它元素的变动比list 要多,并且它是排序的,每次插入和删除都需要对元素重新排序;

2, 关联容器对元素的检索操作比vector 慢,但是比list 要快很多。vector 是顺序的连续存储,当然是比不上的,但相对链式的list 要快很多是因为list 是逐个搜索,它搜索的时间是跟容器的大小成正比,而关联容器 查找的复杂度基本是Log(N) ,比如如果有1000 个记录,最多查找10 次,1,000,000 个记录,最多查找20 次。容器越大,关联容器相对list 的优越性就越能体现;

3, 在使用上set 区别于vector,deque,list 的最大特点就是set 是内部排序的,这在查询上虽然逊色于vector ,但是却大大的强于list 。

4, 在使用上map 的功能是不可取代的,它保存了“键- 值”关系的数据,而这种键值关系采用了类数组的方式。数组是用数字类型的下标来索引元素的位置,而map 是用字符型关键字来索引元素的位置。在使用上map 也提供了一种类数组操作的方式,即它可以通过下标来检索数据,这是其他容器做不到的,当然也包括set 。(STL 中只有vector 和map 可以通过类数组的方式操作元素,即如同ele[1] 方式)

容器适配器

STL 中包含三种适配器:栈stack 、队列queue 和优先级priority_queue

适配器是容器的接口,它本身不能直接保存元素,它保存元素的机制是调用另一种顺序容器去实现,即可以把适配器看作“它保存一个容器,这个容器再保存所有元素”。

STL 中提供的三种适配器可以由某一种顺序容器去实现。默认下stack 和queue 基于deque 容器实现,priority_queue 则基于vector 容器实现。当然在创建一个适配器时也可以指定具体的实现容器,创建适配器时在第二个参数上指定具体的顺序容器可以覆盖适配器的默认实现。

由于适配器的特点,一个适配器不是可以由任一个顺序容器都可以实现的。

栈stack 的特点是后进先出,所以它关联的基本容器可以是任意一种顺序容器,因为这些容器类型结构都可以提供栈的操作有求,它们都提供了push_back 、pop_back 和back 操作;

队列queue 的特点是先进先出,适配器要求其关联的基础容器必须提供pop_front 操作,因此其不能建立在vector 容器上;

优先级队列priority_queue 适配器要求提供随机访问功能,因此不能建立在list 容器上。


转载于:https://www.cnblogs.com/tham/p/6827226.html

相关文章:

flutter开发中常用的dart插件

flutter插件官网地址:https://pub.dartlang.org/packages/ 1. image_picker 一个可以从图库选择图片,并可以用相机拍摄新照片的flutter插件 2. flutter_image 使用NetworkImageWithRetry 代替Image.network 加载网络图片可获得重试能力。 3. barcode_sca…

XML(eXtensible Markup Language)文件的解析

XML与HTML一样,文件中除了根节点以外,整个文件包含一个隐含根“/”,所以我们在解析文件同时一般采用XPath语法进行解析时,一般首先要以反“/”开始。 转载于:https://www.cnblogs.com/hibernate3-example/archive/2010/10/20/2492356.html

JavaScript 立即执行函数的两种写法

(function(str){console.log(str欢迎你~);})(行步至春深);(function(str) {console.log(str欢迎你~);}(行路易知难)); 可以看到,每种写法都比平常多出两个小括号,其中一个可以看作是调用,里面装参数,另一个可以看作防止语法错误。…

【Android动画】之Tween动画 (渐变、缩放、位移、旋转)

Android 平台提供了两类动画。 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变)。 第二类就是 Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似。 下面就讲一下…

Mac下PHP7.1+Nginx安装和配置

https://blog.csdn.net/haiyanggeng/article/details/79186982 PHP:7.1.13Nginx:1.12.2 1. 安装PHP# 添加源brew tap homebrew/dupesbrew tap homebrew/versionsbrew tap homebrew/homebrew-php#更新源brew update#安装brew install php71 --with-imap -…

黑木耳的功效是什么

黑木耳,生长在朽木上,形似人的耳朵,色黑或褐黑,故名黑木耳,又名木菌、树鸡。黑木耳营养极为丰富,据史料记载,它是上古时代帝王独享之佳品,含有大量的碳水化合物、蛋白质、铁、钙、磷…

Javascript 移动的海绵宝宝

效果描述&#xff1a; 做一个简单的动画效果&#xff0c;刚刷新页面时&#xff0c;SpongeBob在页面的左上角位置&#xff0c;随着时间推移&#xff0c;他匀速向右移动&#xff0c;直到右侧抵达页面右侧停下来。 分析&#xff1a; SpongeBob作为一张图片被存放在<img>里…

sqlserver任务导出Excle

--sql语句就用下面的存储过程 /*--数据导出Excel 导出查询中的数据到Excel,包含字段名,文件为真正的Excel文件,如果文件不存在,将自动创建文件,如果表不存在,将自动创建表基于通用性考虑,仅支持导出标准数据类型 使用方法&#xff1a; 直接复制执行创建储存过程-&#xff0d;陈…

Oracle集合操作

Oracle集合操作 UNION&#xff1a;并集&#xff0c;所有的内容都查询&#xff0c;重复的显示一次 UNION ALL&#xff1a;并集&#xff0c;所有的内容都显示&#xff0c;包括重复的 INTERSECT&#xff1a;交集&#xff1a;只显示重复的 MINUS&#xff1a;差集&#xff1a…

Mongodb 4.0+安装

mongodb 4.0&#xff1a;windows 环境选择默认安装路径&#xff1b;存储文件夹自定义&#xff1a; 1.原配置文件删除.mp2.data下新建db文件夹 Mongod -- dbpath D:MongoDB/data3.&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;close windows防火墙&#xff08;…

JavaScript 慢慢移动的海绵宝宝

前情提要&#xff1a;Javascript 移动的海绵宝宝 这个海绵宝宝是匀速运动、突然停下来的&#xff0c;有点不合理。现实中我们跑步都是速度慢慢减小到0。 要实现这个效果&#xff0c;就必须速度逐渐减小&#xff0c;本质上是盒子的步长逐渐减小。 step (targetLocation - nowL…

Linux(CentOS)目录操作命令、文件操作命令、压缩解压缩命令

一、目录操作命令  ls命令    — 功能说明&#xff1a;显示文件和目录列表。    — 命令格式&#xff1a;ls [参数] [<文件或目录> …]    — 常用参数&#xff1a;      -a : 不隐藏任何以“.”字符开始的条目。      -b : 用八进制形式显示非打…

阿里巴巴持续投入,etcd 正式加入 CNCF

2018 年 12 月 11 日&#xff0c;在 KubeCon CloudNativeCon 北美峰会上&#xff0c;etcd 项目正式加入云原生计算基金会&#xff08;CNCF&#xff09;。CNCF 是一个厂商中立的基金会、云原生技术推广和普及的领导者。 etcd 在 2013 年由李响&#xff0c;Brandon Philips, Al…

小机上监控AIX和数据库管理系统的运行情况直到性能优化(SQL语句优化和排除硬件问题)...

AIX下的命令 1)topas 检测操作系统的运行状况 2)nmon(c--cpu,m--memory,d--disk) 检测这3个的情况 ORACLE下的命令 提示&#xff1a;下面这些视图都是实时监控生产机上数据库的情况查询结果每个时刻都随数据库系统当时的情况在变化 &#xff08;1&#xff09; selectopname,…

从前端框架到前端架构参考资料

参考资料 • Wiki - MVC https://zh.wikipedia.org/wiki/MVC • Wiki - MVVM https://zh.wikipedia.org/wiki/MVVM • Mustach https://github.com/janl/mustache.js#usage • Handlebars Introduction | Handlebars • React React – A JavaScript library for building us…

(转)(c#)数据结构与算法分析 --树

树 首先&#xff0c;在win下&#xff0c;进入命令行&#xff0c;输入tree&#xff0c;它会以树的形式返回当前文件夹下的所有子文件夹及文件。如上图&#xff0c;就是一个树。就像一棵被颠倒过来的苹果树&#xff0c;每一个元素称之为节点&#xff0c;如图&#xff0c;A就是这棵…

.vimrc文件

1 set number 2 set shiftwidth4 3 set softtabstop4 4 set tabstop4 5 set expandtab 6 "set hlsearch 7 set noerrorbells 8 set smartindent 9 set autoindent 10 set nobackup 11 syntax on 12 filetype on 13 filetype plugin on 14 filetype indent on转载于:https:…

Javascript中undefined,NaN等特殊比较

以下内容转自&#xff1a;http://blog.csdn.net/hongweigg/article/details/380900931、问题&#xff1a;在Javascript中&#xff0c;typeof(undefined) undefined成立吗&#xff1f; 答案&#xff1a;不成立&#xff0c;全局函数 typeof()返回值类型为字符串类型&#xff0c;…

ECMAScript 6 模板字面量的常见用法

模板字面量可以理解成是字符串的一种&#xff0c;形式上用反引号 将内容括起来。 目录 特点一&#xff1a;模板字面量会保留反引号内部的空格、回车、tab,会将\n,\t翻译。 特点二&#xff1a;支持字符串插值 特点三&#xff1a;和标签函数搭配食用 特点一&#xff1a;模板…

Pycharm去掉项目所有 # 注释

通过快捷键ctrlshiftR 进入 项目全局替换窗口&#xff0c;点击右上角 勾选正则&#xff0c;然后 搜索框输入 (#.*) 即可 &#xff0c;然后点击 replace all 去掉所有注释 转载于:https://www.cnblogs.com/rgcLOVEyaya/p/RGC_LOVE_YAYA_890days.html

引擎设计跟踪(九.14.2i) Android GLES 3.0 完善

最近把渲染设备对应的GLES的API填上了. 主要有IRenderDevice/IShader/ITexture/IGraphicsResourceManager/IIndexBuffer/IVertexBuffer.都是体力活, 根据文档(https://www.khronos.org/opengles/sdk/docs/man3/)填上对应的API就可了.遇到的问题纪录在下面: Stick to the standa…

NUnit在VS2008中的安装使用

声明&#xff1a;在方法二中图片可以显示不完整&#xff0c;读者可以将图片保存到本地查看。看完再删除了。方法一为转载的。方法二是自己写的。 方法一、 1、从NUnit官网&#xff08;http://www.nunit.org/index.php&#xff09;下载最新版本NUnit&#xff0c;当前版本为NUnit…

Egg 初学笔记

egg是什么 egg.js简称egg&#xff0c;属于小而美的框架&#xff0c;不直接提供功能&#xff0c;它拥有强大的插件机制&#xff0c;扩展性好&#xff0c;egg基于koa(https://eggjs.org/zh-cn/intro/egg-and-koa.html)开发&#xff0c;可基于egg制定上层框架。 Koa特点 提供很好…

HttpModule与HttpHandler详解

ASP.NET对请求处理的过程&#xff1a;当请求一个*.aspx文件的时候&#xff0c;这个请求会被inetinfo.exe进程截获&#xff0c;它判断文件的后缀&#xff08;aspx&#xff09;之后&#xff0c;将这个请求转交给 ASPNET_ISAPI.dll&#xff0c;ASPNET_ISAPI.dll会通过http管道&…

《梦断代码Dreaming In Code》阅读笔记(三)

最后这几章感觉上更多是从软件完成整体上来讲的。比如说技术、方法等。 在我看来&#xff0c;其实一个团队一直坚持一种好的、先进的方法是不可少的。如果一个优秀的团队刚愎自用&#xff0c;只随着成员们喜好发展&#xff0c;那不能长久。比如说&#xff0c;在开发软件工程课程…

个人建议之PHP面试的准备

你好&#xff0c;是我琉忆——PHP程序员面试笔试系列图书的作者。 随着越来越多的人开始迈入PHP开发工程师的队列&#xff0c;不管是一个PHP新手还是一个有一两年开发经验的PHPer都不得不去面对找工作前面试这件事。 我现在以个人对面试的经历和见解来全面的对PHP面试考点PHP真…

关于2D互动技术的一些要点

没有动画的程序很难称作是互动产品。 2D图形技术主要涵盖 动画原理 动画是定时器改变元素属性&#xff0c;渲染引擎重新渲染的过程。 动画的本质是 关于时间的函数 PS:右图就是一个快进慢出的动画 动画的要素

Xamarin开发Anroid应用介绍

第1章 Xamarin开发Anroid应用介绍 如今智能手机已经盛行了好几年&#xff0c;而针对这些智能手机的软件开发也变得异常火热。但是在Android平台下只能使用Java开发&#xff0c;iOS平台下也只能使用Objective-C或Swift开发本文选自Xamarin Android开发实战上册。 对于那些C#程序…

忘记Rxjava吧,你应该试试Kotlin的协程

0.前言 协程以前一直是Kotlin作为实验性的一个库&#xff0c;前些日子发现1.3版本的kotlin relese了协程&#xff0c;所以就找时间研究了一下&#xff0c;本来早就想写这篇文章了&#xff0c;但是因为离职换工作的原因&#xff0c;迟迟未能动笔&#xff0c;这两天终于算搞完了&…

数据可视化相关网站

D3 gallery Gallery / D3 / Observable Flowing Data / NYTimes / … FlowingData | Data Visualization and Statistics Data Video Explorer Data Video Explorer 配色网站 配色网站 Material Design Color, Flat Colors, Icons, Color Palette | Material UI Colo…