【C++基础】STL——常用序列式容器详解

序列式容器

所谓STL序列式容器,其共同的特点是不会对存储的元素进行排序,元素排列的顺序取决于存储它们的顺序。不同序列式容器的适用场景不同。常用的序列式容器有:array、vector、deque、list

序列式容器共有函数:

下面是序列式容器的共有方法、主要是基于迭代器的一些方法和一些常用的方法。

迭代器成员函数

迭代器是什么?

成员函数功能
begin()返回指向容器中第一个元素的随机访问迭代器。
end()返回最后一个元素的后一个位置的随机访问迭代器
rbegin()返回指向最后一个元素的随机访问迭代器
rend()返回指向第一个元素之前一个位置的随机访问迭代器。
cbegin()begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
cend()end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crbegin()rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crend()rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

常用其他成员函数

成员函数功能
size()返回容器中当前元素的数量,初始值通常为容器构造函数的第二个参数
empty()判断容器是否为空,和通过 size()==0 的判断条件功能相同,但其效率更快
at(n)返回容器中 n 位置处元素的引用
自动越界检查,越界则抛出 out_of_range 异常。list容器没有此成员函数
erase()移出一个元素或一段元素
clear()移出所有的元素,容器大小变为 0
insert()在指定的位置插入一个或多个元素
array由于不能添加元素,不支持
resize()改变实际元素的个数
array由于固定长度,不支持
swap()交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的
如果是array,还需要保证长度相等
front()返回容器中第一个元素的直接引用该函数不适用于空的 array 容器
back()返回容器中最后一个元素的直接应用,该函数同样不适用于空的 array 容器

<1> array

array 容器是 C++ 11 标准中新增的序列容器,简单地理解,它就是在 C++ 普通数组的基础上,添加了一些成员函数和全局函数。在使用上,它比普通数组更安全,且效率并没有因此变差。

array 容器以类模板的形式定义在 <array> 头文件,并位于命名空间 std 中

namespace std{
    template <typename T, size_t N>
    class array;
}

初始化

头文件:#include<array>
创建具有 4 个 int 类型元素的 array 容器,但是array不会初始化默认值,里面的值是不确定的

std::array<double, 10> values; 

所以要创建初始化为0的array容器要采用下面的方式:

std::array<double, 10> values {};

也可以像创建常规数组那样对元素进行初始化:

std::array<double, 10> values {0.5,1.0,1.5,,2.0};

array 特有常用函数

成员函数功能
fill(val)将 val 赋值给容器中的每个元素
operator[ ]array 重载了[]运算符,意味着array也可以像访问数组一样使用[]访问元素
data()返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能

<2> vector

vector 容器是 STL 中最常用的容器之一,它和 array 容器非常类似,都可以看做是对 C++ 普通数组的“升级版”。不同之处在于,array 实现的是静态数组(容量固定的数组),而 vector 实现的是一个动态数组,即可以进行元素的插入和删除,在此过程中,vector 会动态调整所占用的内存空间,整个过程无需人工干预。

该容器擅长在尾部插入或删除元素,在常量时间内就可以完成,时间复杂度为O(1);而对于在容器头部或者中部插入或删除元素,则花费时间要长一些(移动元素需要耗费时间),时间复杂度为线性阶O(n)。原因在于其是基于数组的数据结构。

vector 容器以类模板 vector( T 表示存储元素的类型)的形式定义在 <vector> 头文件中,并位于 std 命名空间中。

初始化

头文件:#include <vector>
初始化一个 向量数组 vec

vector<int> vec;

可以调用其构造函数指定一个初始容量为10的vector

vector<int> vec(10);

或者 利用其成员函数reserve()改变容量为10

   	vector<int> vec;
   	vec.reserve(10);

也可以像数组一样初始化(C++11 新增)

vector<int>vec = {1,2,3,4,5};

vector常用函数

成员函数功能
push_back()在序列的尾部添加一个元素,复杂度仅O(1)
pop_back()移出序列尾部的元素,复杂度仅O(1)
capacity()返回当前容量,vector是动态数组,所以有size(实际元素个数)和capacity(容量)两个属性
operator[ ]重载了 [ ] 运算符,可以向访问数组中元素那样访问元素
assign()用新元素替换原有内容

<3>deque

双端队列deque(double-end-queue),和vector非常相似,都是通过动态数组管理内存,支持随机访问,并且和vector用相同的接口。不同点在于,deque的头尾两端都是开放的。因此,deque在头尾插入和删除都是O(1)。

  • deque 容器中存储元素并不能保证所有元素都存储到连续的内存空间中,因为deque中存储的是元素的指针,而非元素本身(详情)
  • deque不支持内存重新分配控制,因此,当有元素插入到容器中间时(非两端),那么这时候指向deque的指针、迭代器和引用都会失效!

deque 的使用场景:

  1. 需要在容器前后两端插入和删除元素的时候

  2. 不需要指向容器中的元素

初始化

deque的初始化方式与vector差不多,有以下几种:
头文件:#include <deque>
创建一个空的deque容器 (常用方式)

std::deque<int> deq;

也可以创建一个 初始长度为10的队列,里面的元素为对应类型的默认值

deque<int> deq(10); 

还可以创建一个具有 n 个元素的 deque 容器,并为每个元素都指定初始值

deque<int> deq(10,2);

deque常用函数

deque的成员函数用法与vector差不多,最大的差别在于:deque里面没有capacity()函数

成员函数功能
push_back()在序列的尾部添加一个元素
push_front()在序列的头部添加一个元素
pop_back()移出序列尾部的元素
pop_front()移除容器头部的元素
emplace_front()在容器头部生成一个元素。和 push_front() 的区别是,
该函数直接在容器头部构造元素,省去了复制移动元素的过程。
emplace_back()在容器尾部生成一个元素。和 push_back() 的区别是
该函数直接在容器尾部构造元素,省去了复制移动元素的过程。

deque 的特殊底层原理

和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。为了管理这些连续空间,deque 容器用数组存储着各个连续空间的首地址。也就是说, 数组中存储的都是指针,指向那些真正用来存储数据的各个连续空间。
deque

当 deque 容器需要在头部或尾部增加存储空间时,它会申请一段新的连续空间,同时在 map 数组的开头或结尾添加指向该空间的指针,由此该空间就串接到了 deque 容器的头部或尾部。

<4>list

list是一个双向链表(doubly linked list),list的内部结构和vector,array,deque完全不同。list里面有两个指针(anchors),分别指向第一个元素和最后一个元素,每个元素都有指向自己前驱和后驱的指针。基于这样的存储结构,list 容器具有一些其它容器(array、vector 和 deque)所不具备的优势,即它可以在序列已知的任何位置快速插入或删除元素(时间复杂度为O(1))。并且在 list 容器中移动元素,也比其它容器的效率高。

初始化

list 的创建方式和deque的方式完全一样:
头文件:#include <list>
创建一个空的list容器 (常用方式)

std::list<int> l;

也可以创建一个 初始长度为10的队列,里面的元素为对应类型的默认值

list<int> l(10); 

还可以创建一个具有 n 个元素的 deque 容器,并为每个元素都指定初始值为2

list<int> l(10,2);

list 常用函数

成员函数功能
push_front()在容器头部插入一个元素
pop_front()删除容器头部的一个元素
push_back()在容器尾部插入一个元素
pop_back()删除容器尾部的一个元素
insert()在容器中的指定位置插入元素。
emplace_front()在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高
emplace_back()在容器尾部直接生成一个元素。该函数和 push_back() 的功能相同,但效率更高。
splice()将一个 list 容器中的元素插入到另一个容器的指定位置。
remove(val)删除容器中所有等于 val 的元素。
remove_if()删除容器中满足条件的元素。
sort()通过更改容器中元素的位置,将它们进行排序。
merge()合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。

forward_list

forward_list 是 C++ 11 新添加的一类容器,其底层实现和 list 容器一样,采用的也是链表结构,只不过 forward_list 使用的是单链表,而 list 使用的是双向链表

整理资源来自:C语言中文网

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流水线程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值