贵阳网站建设运营,购物网站销售管理,大学生平面设计作品集,dwcc2018怎么做网站STL标准容器类简介
标准容器类说明顺序性容器vector从后面快速的插入与删除#xff0c;直接访问任何元素deque从前面或后面快速的插入与删除#xff0c;直接访问任何元素list双链表#xff0c;从任何地方快速插入与删除关联容器set快速查找#xff0c;不允许重复值multise…
STL标准容器类简介
标准容器类说明顺序性容器vector从后面快速的插入与删除直接访问任何元素deque从前面或后面快速的插入与删除直接访问任何元素list双链表从任何地方快速插入与删除关联容器set快速查找不允许重复值multiset快速查找允许重复值map一对多映射基于关键字快速查找不允许重复值multimap一对多映射基于关键字快速查找允许重复值容器适配器stack后进先出queue先进先出priority_queue最高优先级元素总是第一个出列 所有标准库共有函数 默认构造函数提供容器默认初始化的构造函数。复制构造函数将容器初始化为现有同类容器副本的构造函数析构函数不再需要容器时进行内存整理的析构函数empty容器中没有元素时返回true,否则返回falsemax_size返回容器中最大元素个数size返回容器中当前元素个数operator将一个容器赋给另一个容器operator如果第一个容器小于第二个容器返回true否则返回falseoperator如果第一个容器小于或等于第二个容器返回true否则返回falseoperator如果第一个容器大于第二个容器返回true否则返回falseoperator如果第一个容器大于或等于第二个容器返回true否则返回falseoperator如果第一个容器等于第二个容器返回true否则返回falseoperator!如果第一个容器不等于第二个容器返回true否则返回falseswap交换两个容器的元素 其中operator,operator,operator,operator,operator,operator!均不适用于priority_queue
顺序容器和关联容器共有函数 begin该函数两个版本返回iterator或const_iterator引用容器第一个元素end该函数两个版本返回iterator或const_iterator,引用容器最后一个元素后面一位rbegin该函数两个版本返回reverse_iterator或const_reverse_iterator,引用容器最后一个元素rend该函数两个版本返回reverse_iterator或const_reverse_iterator引用容器第一个元素前面一位erase从容器中清除一个或几个元素clear清除容器中所有元素 下表显示了顺序容器和关联容器中常用的typedef这些typedef常用于变量、参数和函数返回值的一般性声明。 value_type容器中存放元素的类型reference容器中存放元素类型的引用const_reference容器中存放元素类型的常量引用这种引用只能读取容器中的元素和进行const操作pointer容器中存放元素类型的指针iterator指向容器中存放元素类型的迭代器const_iterator指向容器中存放元素类型的常量迭代器只能读取容器中的元素reverse_iterator指向容器中存放元素类型的逆向迭代器这种迭代器在容器中逆向迭代const_reverse_iterator指向容器中存放元素类型的逆向迭代器只能读取容器中的元素difference_type引用相同容器的两个迭代器相减结果的类型list和关联容器没有定义operator-size_type用于计算容器中项目数和检索顺序容器的类型不能对list检索 什么是容器
首先我们必须理解一下什么是容器在C 中容器被定义为在数据存储上有一种对象类型它可以持有其它对象或指向其它对像的指针这种对象类型就叫做容器。很简单容器就是保存其它对象的对象当然这是一个朴素的理解这种“对象”还包含了一系列处理“其它对象”的方法因为这些方法在程序的设计上会经常被用到所以容器也体现了一个好处就是“容器类是一种对特定代码重用问题的良好的解决方案”。
容器还有另一个特点是容器可以自行扩展。在解决问题时我们常常不知道我们需要存储多少个对象也就是说我们不知道应该创建多大的内存空间来保存我们的对象。显然数组在这一方面也力不从心。容器的优势就在这里它不需要你预先告诉它你要存储多少对象只要你创建一个容器对象并合理的调用它所提供的方法所有的处理细节将由容器来自身完成。它可以为你申请内存或释放内存并且用最优的算法来执行您的命令。
容器是随着面向对象语言的诞生而提出的容器类在面向对象语言中特别重要甚至它被认为是早期面向对象语言的基础。在现在几乎所有的面向对象的语言中也都伴随着一个容器集在C 中就是标准模板库STL 。
和其它语言不一样C 中处理容器是采用基于模板的方式。标准C 库中的容器提供了多种数据结构这些数据结构可以与标准算法一起很好的工作这为我们的软件开发提供了良好的支持
通用容器的分类
STL 对定义的通用容器分三类顺序性容器、关联式容器和容器适配器。
顺序性容器 是一种各元素之间有顺序关系的线性表是一种线性结构的可序群集。顺序性容器中的每个元素均有固定的位置除非用删除或插入的操作改变这个位置。这个位置和元素本身无关而和操作的时间和地点有关顺序性容器不会根据元素的特点排序而是直接保存了元素操作时的逻辑顺序。比如我们一次性对一个顺序性容器追加三个元素这三个元素在容器中的相对位置和追加时的逻辑次序是一致的。
关联式容器 和顺序性容器不一样关联式容器是非线性的树结构更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。但是关联式容器提供了另一种根据元素特点排序的功能这样迭代器就能根据元素的特点“顺序地”获取元素。
关联式容器另一个显著的特点是它是以键值的方式来保存数据就是说它能把关键字和值关联起来保存而顺序性容器只能保存一种可以认为它只保存关键字也可以认为它只保存值。这在下面具体的容器类中可以说明这一点。
容器适配器 是一个比较抽象的概念 C的解释是适配器是使一事物的行为类似于另一事物的行为的一种机制。容器适配器是让一种已存在的容器类型采用另一种不同的抽象类型的工作方式来实现的一种机制。其实仅是发生了接口转换。那么你可以把它理解为容器的容器它实质还是一个容器只是他不依赖于具体的标准容器类型可以理解是容器的模版。或者把它理解为容器的接口而适配器具体采用哪种容器类型去实现在定义适配器的时候可以由你决定。
下表列出STL 定义的三类容器所包含的具体容器类 标准容器类 特点 顺序性容器 vector 从后面快速的插入与删除直接访问任何元素 deque 从前面或后面快速的插入与删除直接访问任何元素 list 双链表从任何地方快速插入与删除 关联容器 set 快速查找不允许重复值 multiset 快速查找允许重复值 map 一对多映射基于关键字快速查找不允许重复值 multimap 一对多映射基于关键字快速查找允许重复值 容器适配器 stack 后进先出 queue 先进先出 priority_queue 最高优先级元素总是第一个出列 顺序性容器 向量 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 容器上。 vector
一种随机访问的数组类型他提供了对数组元素的快速、随机访问以及在序列尾部快速、随机的插入和删除操作。它在需要时可以改变其大小也就是说大小可变的向量比较灵活。可取代C语言本身提供的传统数组。提供随机存储能力。操作尾端元素的速度最快。由于所有元素占用连续空间所以一旦进行插入或者删除动作有可能使原本的某些 iterators失效。
list:
这是一个双向链表容器完成了标准的C数据结构中链表的所有功能。它不支持随机访问的数组类型因为STL以双向链表的方式实现list对象所以访问链表元素要指针从链表的某个端点开始。插入和删除操作所花的时间是固定的也就是说list对象插入和删除一个元素所需要的时间与该元素在链表中的位置无关。在任何位置做插入和删除动作都很快不像vector只局限于尾端而deque只局限于两端才有高效率。由于各元素并不占用连续空间所以一旦进行插入或者删除动作原本的iterators任然有效。注意许多只在元素搬移的STL algorithms用于list身上会有不佳的效率。幸好这些STL algorithms 都有对应的list member functions 可以替代。后者之所以会有比较好的效率原因是他们只操作指标而非真正去拷贝或者移动元素。
queue:
这是一种队列容器它采用deque和list对象创建一个先进先出(FIFO)的容器它实际上完成了标准的C数据结构中的队列所有功能。不提供随机存储能力。行为与特性都很类似vector但因为是双向开口所以操作两端元素的速度都很快不像vectoer只在操作尾端元素时才有高效率。由于所有元素占用连续空间所以一旦进行插入或者删除动作有可能是原本的某些iterators失效。
stack:
这是一种栈容器完成了标准的C数据结构中栈的所有功能。也就是说它通过vector、deque或者list对象创建了一个先进后出的容器。stack特性是先进后出(FILO: First In, Last Out)。
deque:
这是一种随机访问的数据类型提供了在序列两端快速插入和删除操作的功能他可以再需要的时候修改器自身大小。也就是说这是一种双端队列容器完成了标准的C数据结构中队列的所有功能。queue特性是先进先出。
priority_queue:
这是一种按值排序的队列容器。它使用vector或者deque对象创建了一个排序队列。priority_queue特性是依优先权来谁是下一个元素。
set:
这是一种随机存取的集合容器。其关键词和数据元素是同一个值也就是说它不能包含重复的元素。set经过排序的结构体以某个可指定的排序方式排序每个元素第一无二。由于已经排序所以搜寻速度极快。但也因此不允许我们直接修改某个元素的内容因为这可能会影响排序。修改元素内容的正确的作法是先将该元素删除再加入此时使用新值。set通常是以平衡二叉树(balanced binary tree)来存储但并不是强制规定甚至是以red-black trees来完成。
multiset:
其关键词和数据元素也是同一个值但和set不同的以及最大的区别在于这是一种允许出现重复元素的集合容器。multiset允许元素重复。
map:
其是一种关联数组容器它包含成对数据的容器其中一个值是实际数据值另外一个是用来寻找数据的关键值一个特定的关键词只能与一个元素相关联。map是由一对一对的键值key/value所组成的排序结构体键值独一无二。map通常是以balanced binary tree来实现但并不强制规定。事实上map的内部结构通常与set是一样的因此我们可以将set视为一种特殊的map其键值和实值是相同的所以map和set几乎拥有完全相同的能力。
multimap:
这是一种允许出现重复关键之的关联数组容器然而与map对象不同它的一个关键词可以与多个元素相联系multimap允许键值重复。
hash table:
这并不是C Standard规范内的一容器因标准委员会作业时间的关系但是它对于大量数据的搜索而言很实用也很重要。有许多STL实作品例如SGI都涵盖了它。通常STL产品厂商会提供4中hash tables: hash_set、hash_multiset、hash_map、hash_multimap。