STL容器

STL容器

Standard Template Library 标准模板库

容器是STL的核心部件之一,是迭代器的依附,是算法作用的目标。主要由头文件vector, list, deque, set, map, stack和queue组成.

  • STL中的容器可分为顺序容器(Sequence Container)和关联容器(Associative Container)。
  • 容器适配器(Container Adaptor)是对顺序容器(Sequence Container)或关联容器(Associative Container)进行包装而得到的一种功能更强大的容器(由其它容器实现的容器)。

下列出STL中的主要(标准和非标准的)容器:

  1. 顺序容器:是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定。顺序容器包括:vector(向量)、list(列表)、deque(队列)。
  2. 关联容器:关联式容器是非线性的树结构,更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。关联容器包括:map(集合)、set(映射)、multimap(多重集合)、multiset(多重映射)。
  3. 容器适配器:容器适配器让一种已存在的容器类型采用另一种不同的抽象类型的工作方式实现。适配器是容器的接口,它本身不能直接保存元素,它保存元素的机制是调用另一种顺序容器去实现。STL 中包含三种适配器:栈stack 、队列queue 和优先级队列priority_queue 。

底层结构

  • vector:底层是动态数组,把数组的常用操作封装起来,方便使用,插入性能为O(n),尾插为O(1)。
  • list:底层是双向链表,在当前结点前后插入新元素的效率为O(1);如果有序插入,退化为O(n),因为需要遍历比较元素值。
  • deque:主要是和 vector 相比较,从头部插入的性能优于 vector。
  • set:底层是红黑树,要求存储的数据是可比较的,插入性能是log(n),树的平衡调整会有一定的开销。
  • map:底层是红黑树,存储的数据类型是 pair 键值对;和 set 相比,map 对存储的用户数据的要求没那么高,而把要求转移到键上。
  • pair:通常是 map 的存储数据类型,只能存储两个值。
  • priority_queue:底层是堆结构(大小顶堆),优先队列是队列结构和有序存储的结合,保证队首元素是当前的极值。

容器操作

  • deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque支持从头部插入数据:push_front()。
  • map与multimap差别在于multiple允许一个键对应多个值。对于迭代器来说,可以修改value,而不能修改key。Map会根据key自动排序。
  • set的含义是集合,它是一个有序的容器,里面的元素都是排序好的,默认自动排序,支持插入,删除,查找等操作。所有的操作的都是严格在logn时间之内完成,效率非常高。set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同。

各种容器的元素在内存中的储存方式

  • vector(向量):相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,由于它的特性完全可以将vector 看作动态数组。在创建一个vector 后,它会自动在内存中分配一块连续的内存空间进行数据存储,初始的空间大小可以预先指定也可以由vector 默认指定,这个大小即capacity函数的返回值。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,效率非常低。
  • list(列表):是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。
  • deque(队列):它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小,它不需要重新分配空间。
  • set, multiset, map, multimap 是一种非线性的树结构,具体的说采用的是一种比较高效的特殊的平衡二叉搜索树—红黑树结构。

各种容器优劣

  • Vector:
    优点:
    A、支持随机访问,访问效率高和方便,它像数组一样被访问,即支持[ ] 操作符和vector.at()。
    B、节省空间,因为它是连续存储,在存储数据的区域都是没有被浪费的,但是要明确一点vector 大多情况下并不是满存的,在未存储的区域实际是浪费的。
    缺点:
    A、在内部进行插入、删除操作效率非常低。
    B、只能在vector 的最后进行push 和pop ,不能在vector 的头进行push 和pop 。
    C、 当动态添加的数据超过vector 默认分配的大小时要进行内存的重新分配、拷贝与释放,这个操作非常消耗能。
  • List:
    优点:
    不使用连续的内存空间这样可以随意地进行动态操作,插入、删除操作效率高;
    缺点:
    A、不能进行内部的随机访问,即不支持[ ] 操作符和vector.at(),访问效率低。
    B、相对于verctor 占用更多的内存。
  • Deque:
    优点:
    A、支持随机访问,方便,即支持[ ] 操作符和vector.at() ,但性能没有vector 好;
    B、可以在两端进行push 、pop 。
    缺点:
    在内部进行插入、删除操作效率低。

综合:

  • vector 的查询性能最好,并且在末端增加数据也很好,除非它重新申请内存段。
  • list 是一个链表,任何一个元素都可以是不连续的,但它都有两个指向上一元素和下一元素的指针。所以它对插入、删除元素性能是最好的,而查询性能非常差;适合大量地插入和删除操作而不关心随机存取的需求。
  • deque 是介于两者之间,它兼顾了数组和链表的优点,它是分块的链表和多个数组的联合。所以它有比list好的查询性能,有比vector好的插入、删除性能。 如果你需要随即存取又关心两端数据的插入和删除,那么deque是最佳之选。
  • 关联容器的特点,相对于顺序容器:
    A 其内部实现是采用非线性的二叉树结构,具体是红黑树的结构原理实现的;
    B set 和map 保证了元素的唯一性,mulset 和mulmap 扩展了这一属性,可以允许元素不唯一;
    C 元素是有序的集合,默认在插入的时候按升序排列。

总结

  • A 关联容器对元素的插入和删除操作比vector 要快,因为vector 是顺序存储,而关联容器是链式存储;比list 要慢,是因为即使它们同是链式结构,但list 是线性的,而关联容器是二叉树结构,其改变一个元素涉及到其它元素的变动比list要多,并且它是排序的,每次插入和删除都需要对元素重新排序。
  • B 关联容器对元素的检索操作比vector 慢,但是比list 要快很多。vector 是顺序的连续存储,当然是比不上的,但相对链式的list 要快很多是因为list是逐个搜索,它搜索的时间是跟容器的大小成正比,而关联容器查找的复杂度基本是Log(N) ,比如如果有1000 个记录,最多查找10次,1,000,000 个记录,最多查找20 次。容器越大,关联容器相对list 的优越性就越能体现。
  • C 在使用上set区别于vector,deque,list的最大特点就是set 是内部排序的,这在查询上虽然逊色于vector ,但是却强于list 。
  • D 在使用上map 的功能是不可取代的,它保存了“键- 值”关系的数据,而这种键值关系采用了类数组的方式。数组是用数字类型的下标来索引元素的位置,而map是用字符型关键字来索引元素的位置。在使用上map也提供了一种类数组操作的方式,即它可以通过下标来检索数据,这是其他容器做不到的 。
  • STL 中只有vector 和map可以通过类数组的方式操作元素,即如同ele[] 方式。

STL容器表

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值