C/C++STL学习[1]---顺序容器阐述、对比、选择vector,deque,list,forward_list,array,string

前言

STL系列博客开篇,记录一下自己学C++STL相关的心得。
这篇博客主要是写顺序容器的类型以及各个容器之间的异同还有平时对容器使用的选择。


1. 顺序介绍

顺序容器表示这个容器提供了快速顺序访问元素的能力。

下面是常用的一些顺序容器:

容器名称 简述
vector 可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢
deque 双端队列。支持快速随机访问。在头尾位置插入/删除速度很快
list 双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快
forward_list 单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快
array 固定大小数组。支持快速随机访问。不能添加或删除元素
string 与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入/删除速度快

2. 容器对比说明

array与vector

array就是我们使用的数组。我们一般使用数组的时候都是这样定义的int a[10],这个表示我定义了一个存放int类型数据的数组,数组长度为10。但是我们存放数据的时候,数据会一直增加,很难确定应该给多大的容量才可以保证既不浪费内存又能够满足我们需求。

在我学STL之前,刷题的时候喜欢定义数组。比如要输入20个数据,我就给他定义个25个长度的数组。或者对于不可确定的长度,我往往定义很大的数组。这就导致内存总是过大,影响程序执行时间。

针对这种情况,STL中出现了vector。它解决了array的不可变长度问题。可以把它看成是一个可变长的数组。对于array的数据插入,如果新数据不在尾部插入的话,就意味着数据就要产生移动。比如长度为10的数组,我已存放4个数据,我现在想在第2个位置插入数据,这时候,后面的3,4位数据就要依次往后移动一个单位长度。如果数据量很大,这就导致插入效率很低。vector是array的变形,从定长转向不定长,但是由于存储方式的原因,它还是无法解决这种中途插入带来的效率低问题。但是由于是顺序插入,所以可以用下标的方式进行数据读取。这个就是它的优点:支持快速随机访问。


vector与string

string和vector都是将元素保存在连续的内存空间中。string是专门存放字符的一种vector容器(这是我自己理解的)。所以vector的特性string都有,比如快速随机访问,以及中间插入很慢,尾部插入或者删除很快。


list与forward_list
有前面的连续内存分配方式,就会有分散的内存分配方式。前者的优点是支持快速随机访问,后者就需要依次遍历。后者通常采用链表的方式进行数据存储。

list就是一个双端的链表。这说明list支持头插和尾插。这个和双端队列deque很相似。forward_list直译过来就是前端队列,这说明forward_list只支持从链表头进行插入数据。这两个容器的好处就是解决了上面array,vector,string三种容器插入删除中间元素过慢的问题,因为是链表存储,所以不涉及到依次移动元素。但是元素的访问必须要依次遍历每一个元素。


deque与其他容器
deque是一个双端队列,更加复杂一些。deque存放数据是连续内存分配的方式,所以和string,vector一样,支持快速随机访问。同样的,不可避免的就是中间插入或删除元素的代价可能很高。

但是在deque的两端添加或删除元素都是很快的,与list或forward_list添加删除元素的速度相当。

我个人理解是,deque是既想要有快速访问的效果,但是又想提高元素的插入删除的效率。但由于是内存的连续分配,所以不可避免插入的效率低,只能通过改变插入的位置来提高效率,就有了头尾插法。


3. 容器选择

没学STL之前嘛,那就是直接一个数组,顶多再来个链表搞定所有。学了之后,这么多种容器,怎么选?下面是一些参考意见。

通常使用了STL的话,vector是最好的选择。

  • 除非你有很好的理由选择其他容器,否则应使用vector。
  • 如果你的程序有很多小的元素,且空间的额外开销很重要,则不要使用list或forward_list。
  • 如果程序要求随机访问元素,应使用vector或deque。
  • 如果程序要求在容器的中间插入或删除元素,应使用list 或forward_list。·如果程序需要在头尾位置插入或删除元素,但不会在中间位置进行插入或删除操作,则使用deque。
  • 如果程序只有在读取输入时才需要在容器中间位置插入元素,随后需要随机访问元素,则
    首先,确定是否真的需要在容器中间位置添加元素。当处理输入数据时,通常可以很容易地向vector追加数据,然后再调用标准库的sort函数来重排容器中的元素,从而避免在中间位置添加元素。
    如果必须在中间位置插入元素,考虑在输入阶段使用list,一旦输入完成,将list中的内容拷贝到一个vector中。

如果程序既需要随机访问元素,又需要在容器中间位置插入元素,那该怎么办?答案取决于在list或forward_list中访问元素与vector或deque 中插入/删除元素的相对性能。一般来说,应用中占主导地位的操作(执行的访问操作更多还是插入/删除更多)决定了容器类型的选择。在此情况下,对两种容器分别测试应用的性能可能就是必要的了。
如果你不确定应该使用哪种容器,那么可以在程序中只使用vector和list

公共的操作:使用迭代器,不使用下标操作,避免随机访问。这样,在必要时选择使用vector或list都很方便。


总结

第一次看完之后还是有些笼统,写这篇博客的时候又复盘了一遍,印象更加深刻一些。

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-07 10:14:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-07 10:14:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-07 10:14:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-07 10:14:04       20 阅读

热门阅读

  1. python使用flask框架实现http服务处理

    2023-12-07 10:14:04       36 阅读
  2. Redis 底层数据结构 - 简单动态字符串

    2023-12-07 10:14:04       32 阅读
  3. 【ML】LSTM应用——预测股票(基于 tensorflow2)

    2023-12-07 10:14:04       39 阅读
  4. ffmpeg 同时采集麦克风和摄像头并录制文件

    2023-12-07 10:14:04       25 阅读
  5. RDMA编程实例rdma_cm API

    2023-12-07 10:14:04       25 阅读
  6. Spring Boot 容器如何根据注解加载发现与管理组件

    2023-12-07 10:14:04       27 阅读