序列式容器
概念
序列容器,就是以线性排列(类似普通数组的存储方式)来存储某一指定类型的数据,并且该类容器并不会自动对存储的元素按照值的大小进行排序。
内容
array(数组容器) | 表示可以存储N个T类型的容器,该容器一旦建立那么容量就是固定的,因此不能额外增加或删除元素,只能修改其值 |
vector(向量容器) | 大部分与array类似,但是vector是长度可变的,可以看成是可以动态变化长度的数组,因此在其尾部增加或删除元素效率可以看成是O(1),对其他位置的操作为O(n) |
deque(双端队列容器) | 大部分与vector类似,但是deque在头部插入与删除也是O(1),在其中部插入与删除元素才是O(n) |
list(链表容器) | 一个长度可变的T类型的序列,内部采用双向链表实现,由于双向链表的特性,对其在任何位置插入与删除都将是O(1),但是由于list对应的迭代器类型为双向迭代器,决定了list的访问必须逐个访问,因此对list的访问速度要慢于array、vector和deque |
forward_list(正向链表容器) | 十分接近list,但是内部采用的是单链表实现,因此节省了一定的内存,但是访问也需要逐个访问 |
序列式容器迭代器的通用函数
由于序列式容器(除了forward_list外)都是支持随机访问迭代器的,所以他们有一些通用的对迭代器的操作方法,这里直接给出:
begin() | 返回指向第一个元素的随机访问迭代器 |
end() | 返回指向容器最后一个元素之后一个位置的随机访问迭代器 |
rbegin() | 返回指向最后一个元素的随机访问迭代器 |
rend() | 返回指向第一个元素之前一个位置的随机访问迭代器 |
cbegin() | 和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素 |
举个栗子:
std:: array<int, 5> v{1,2,3,4,5};
for (std::array<int, 5>::iterator it = v.begin(); it != v.end(); it++) {
std::cout << *it << ' ';
}
std::cout << std::endl;//Output 1 2 3 4 5
for (std::array<int, 5>::reverse_iterator it = v.rbegin(); it != v.rend(); it++) {//注意此处需要使用反向迭代器和++
std::cout << *it << ' ';
}
std::cout << std::endl;//Output 5 4 3 2 1
关于这几个对迭代器的操作方法,可以见下图:
![](https://img-blog.csdnimg.cn/47cbafca225e4a03821acbac2c5a6d21.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5piv5LiA5Y-q5bCP5YWU5YWU77yB,size_20,color_FFFFFF,t_70,g_se,x_16)
除此之外对于迭代器的操作,可以使用auto关键字,编译器会自动识别其迭代器的类型。
序列式容器用法
array
array是一种不可以修改其长度,在普通数组的基础上增加了一些全局变量和函数的序列式容器,比起不同数组效率更高更安全。
定义
array的定义:
namespace std{
template <typename T, size_t N>
class array;
}
可以看到array被定义在命名空间std中
因此创建array可以有以下两种方式:
#include<array> //使用array必须导入array头文件
std::array<int, 5> v;
或:
#include<array>
using namespace std;
int main() {
array<int, 5> v;
}
初始化
array的初始化可以采用默认初始化方式:
std:: array<int, 5> v{};//默认初始化
for (std::array<int, 5>::iterator it = v.begin(); it != v.end(); it++) {
std::cout << *it << ' ';
}
//输出5个0
也可以采用类似数组的初始化方式:
std:: array<int, 10> v{1,2,5};
for (std::array<int, 10>::iterator it = v.begin(); it != v.end(); it++) {
std::cout << *it << ' ';
}
//输出1 2 5 0 0 0 0 0 0 0
成员函数
array因为支持随机访问迭代器,所以上文提到的8个操作array都支持
除此之外,array还支持其他几个操作
size() | 返回array中的元素个数,由于array长度是固定的,所以相当于返回构造array的第二个参数N |
max_size() | 返回可容纳元素的最大数量,由于array长度是固定的,所以相当于返回构造array的第二个参数N |
empty() | 返回array是否非空 |
at(i) | 返回array第i个位置(从0开始)的元素的引用,这意味着我们可以直接对他进行修改,并且它会自动检查i是否会导致越界,如果越界会抛出std::out_of_range的异常 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的array容器 |
back() | 返回容器中最后一个元素的直接应用,该函数同样不适用于空的array容器 |
data() | 返回一个指向容器首个元素的指针 |
operator[] | 类似于数组元素的下标访问方式,返回数组对应下标的引用,可以直接操作(包括修改) |
fill(T& val) | 将val赋值给array中的每一个元素,相当于批量赋值,可以用于初始化 |
array1.swap(array2) | 在array1和array2的T与N一致的情况下交换两个array中的元素 |
举个栗子:
std:: array<int, 5> v{1,2,3,4,5};
v[2] = 7;
std::cout << v.at(2) << std::endl;//Output 7
v.at(2) = 5;
std::cout << v.at(2) << std::endl;//Output 5
for (std::array<int, 5>::iterator it = v.begin(); it != v.end(); it++) {//Output 1 2 5 4 5
std::cout << *it << ' ';
}
std::cout << std::endl;
std::cout << v.front() << std::endl;//Output 1
std::cout << v.back() << std::endl;//Output 5
v.fill(10);
for (std::array<int, 5>::iterator it = v.begin(); it != v.end(); it++) {//Output 10 10 10 10 10
std::cout << *it << ' ';
}
std::cout << std::endl;
*(v.data()) = 4;
for (std::array<int, 5>::iterator it = v.begin(); it != v.end(); it++) {//Output 4 10 10 10 10
std::cout << *it << ' ';
}
array相比数组的提升
1.array可以实现大小的比较
大小比较的规则与字符串的大小比较规则一致
std::array<char, 20> h{ "helloworld" };
std::array<char, 20> a{ "apple" };
if (a < h) {//no
std::cout << "yes\n";
}
else {
std::cout << "no\n";
}
2.array可以直接赋值
std::array<char, 20> h{ "helloworld" };
std::array<char, 20> a{ "apple" };
a = h;
for (auto e : a) {//helloworld
std::cout << e;
}
3.at方法可以自动检查边界问题
vector
vector是向量容器,一个向量用于存储同一个类型的一组值
定义
一个向量的定义需要引入如下代码段:
#include <vector>
using namespace std;
或以下列形式创建,(T)是一个类型
#include <vector>
std::vector<T> v;
注意,这样定义的 vector 容器,因为容器中没有元素,所以没有为其分配空间。当添加第一个元素(比如使用 push_back() 函数)时,vector 会自动分配内存。
对于vector,有容量(capacity)和size(大小)的区分。
容量指的是vector能够容纳的最大元素数,这是一个可以拓展的值,通过调用reserve()来拓展容量,如果新的容量小于等于当前容量,那么没有操作,其不会影响原有元素,也不会生成新元素,但是要注意,一旦使用了reserve()那么原油的所有迭代器都将会失效,因为拓展容量时会修改整个vector的地址。
大小指的是vector当前实际容纳的元素数,其也可以修改,通过调用resize()来修改值,如果新的size比容量要大,那么会自动扩容。
初始化
第一种方式,初始化成员列表:
vector<int> v1{1,2,3,4,5};
第二种方式,指定元素个数(默认初始化为0)
vector<int> v2(5);//5个0
第三种方式,指定元素个数并全部初始化为1
vector<int> v3(5,1);//5个1
第四种方式,存储已经存在的vector容器值或数组
vector<int> a(v3); //5个1
vector<int> b(v1.begin(),v1.begin()+3);//1 2 3
int arr[3] = {4,5,6};
vector<int> c(arr,arr+3);//4 5 6
需要注意的是,由于vector是可以直接创建空的vector的,所以这样的初始化是错误的
vector<int> v;
for (auto it = v.begin();it != v.end();it++){
*it = 1;
cout << *it << ' ';
}
//不会报错,但是不会做到预想的结果,因为空的vector的begin() == end()
成员函数
vector因为支持随机访问迭代器,所以上文提到的8个操作vector都支持
除此之外,vector还支持其他几个操作
size() | 返回实际元素个数 |
max_size() | 返回元素个数的最大值。这通常是一个很大的数 |
resize() | 改变实际元素的个数 |
capacity() | 返回当前容量 |
reserve() | 增加容器的容量 |
empty() | 返回vector是否非空 |
at(i) | 返回vector第i个位置(从0开始)的元素的引用,这意味着我们可以直接对他进行修改,并且它会自动检查i是否会导致越界,如果越界会抛出std::out_of_range的异常 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的vector容器 |
back() | 返回容器中最后一个元素的直接应用,该函数同样不适用于空的vector容器 |
data() | 返回一个指向容器首个元素的指针 |
operator[] | 类似于数组元素的下标访问方式,返回数组对应下标的引用,可以直接操作(包括修改) |
assign(val) | 将val赋值给vector中的每一个元素,相当于批量赋值,可以用于初始化 |
push_back() | 在vector的尾部添加一个元素,先创建,然后拷贝移动到vector末尾 |
pop_back() | 移出vector尾部的元素,对于空的vector不适用,移除后size-1,而capacity不变 |
insert() | 在指定的位置插入一个或多个元素,插入后size+1,capacity可能不变 |
erase() | 移出一个元素或一段元素,移除后size减小,capacity不变 |
clear() | 移出所有的元素,容器大小变为 0 |
swap() | 交换两个容器的所有元素/td> |
emplace() | 在指定的位置直接生成一个元素,大小+1 |
emplace_back() | 在vector尾部生成一个元素,由于其是在尾部直接生成而不是拷贝元素或移动,因此效率比push_back高 |
一些例子:
vector<int> v;
cout << v.front() << endl;//Error
cout << v.back() << endl;//Error
cout << v.size() << endl;//Output 0
v.pop_back();//Error
for (auto e : v) {//no Output
cout << e << ' ';
}
cout << v.max_size() << endl;//Output 1073741823
v.resize(10);
cout << v.max_size() << endl;//Output 1073741823
cout << v.size() << endl;//Output 10
for (auto e : v) {//Output 0 0 0 0 0 0 0 0 0 0
cout << e << ' ';
}
其中某些函数存在多个重载,或其调用有其独特的含义,如对参数由特定要求等,这里单独列出:
1.insert
iterator insert(iterator pos,const T& elem) 在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器。
iterator insert(iterator pos,int n,const T& elem) 在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。
iterator insert(iterator pos,first,last) 在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。
iterator insert(iterator pos,initializer_list<T> initlist) 在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。
2.emplace()
该函数与insert很像,都是在某个位置插入元素,但是要注意这个函数一次只能插入一个,同时该函数的效率比insert单次插入要高
iterator emplace(iterator pos,const T& elem)
3.erase()
iterator erase(iterator pos) 删除某个指定位置的元素,返回指向被删除元素下一个位置元素的迭代器 iterator erase(iterator begin,iterator end)删除[begin,end)范围的元素,返回指向被删除元素下一个位置元素的迭代器
void show(vector<int> v) {
for (auto c : v) {
cout << c << ' ';
}
cout << endl;
}
int main() {
vector<int> v{ 1,2,4,5 };
v.insert(v.begin() + 2, 3);
show(v);//1 2 3 4 5
v.insert(v.begin(), 3, 0);
show(v);//0 0 0 1 2 3 4 5
array<int, 2> arr{ 6,7 };
v.insert(v.end(), arr.begin(), arr.end());
show(v);//0 0 0 1 2 3 4 5 6 7
v.insert(v.end(), { 8,9 });
show(v);//0 0 0 1 2 3 4 5 6 7 8 9
v.emplace(v.end(), 10);
show(v);//0 0 0 1 2 3 4 5 6 7 8 9 10
v.erase(v.begin());
show(v);//0 0 1 2 3 4 5 6 7 8 9 10
}
一些小tips
虽然我们创建一个向量vector的时候,理论上这个T可以是任意类型,但是bool类型作为T是会出现问题的因为其牵扯到复杂的历史遗留问题,不做展开。
deque
deque是双端队列容器,其在某些方面与vector高度相似,其对头尾的插入为O(1),对中间位置的插入为O(n),但是其与vector有一个很大的不同在于deque 容器中存储元素并不能保证所有元素都存储到连续的内存空间中。
定义
类似的,deque的创建也有两种方式:
1.
#include<deque>
using namespace std;
deque<int> deq;
2.
#include<deque>
std::deque<int> deq;
注意,这样定义的deque容器,因为容器中没有元素,所以没有为其分配空间。当添加第一个元素(比如使用 push_back() 函数)时,deque 会自动分配内存。
初始化
与vector类似的5种初始化方式
第一种方式,初始化成员列表:
deque<int> v1{1,2,3,4,5};
第二种方式,指定元素个数(默认初始化为0)
deque<int> v2(5);//5个0
第三种方式,指定元素个数并全部初始化为1
deque<int> v3(5,1);//5个1
第四种方式,存储已经存在的deque容器值或数组
deque<int> a(v3); //5个1
deque<int> b(v1.begin(),v1.begin()+3);//1 2 3
int arr[3] = {4,5,6};
deque<int> c(arr,arr+3);//4 5 6
也跟vector一样在某些方面有限制
deque<int> v;
for (auto it = v.begin();it != v.end();it++){
*it = 1;
cout << *it << ' ';
}
//不会报错,但是不会做到预想的结果,因为空的deque的begin() == end()
成员函数
因为deque支持随机访问迭代器,所以上面对随机访问迭代器的8种操作deque都支持
除此之外,deque还支持其他几个操作
size() | 返回实际元素个数 |
max_size() | 返回元素个数的最大值。这通常是一个很大的数 |
resize() | 改变实际元素的个数 |
empty() | 返回deque是否非空 |
shrink _to_fit() | 将内存减少到等于当前元素实际所使用的大小 |
at(i) | 返回deque第i个位置(从0开始)的元素的引用,这意味着我们可以直接对他进行修改,并且它会自动检查i是否会导致越界,如果越界会抛出std::out_of_range的异常 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的deque容器 |
back() | 返回容器中最后一个元素的直接应用,该函数同样不适用于空的deque容器 |
operator[] | 类似于数组元素的下标访问方式,返回数组对应下标的引用,可以直接操作(包括修改) |
assign(val) | 将val赋值给deque中的每一个元素,相当于批量赋值,可以用于初始化 |
push_back() | 在deque的尾部添加一个元素,先创建,然后拷贝移动到deque末尾 |
pop_back() | 移出deque尾部的元素,对于空的deque不适用,移除后size-1,而capacity不变 |
push_front() | 在deque的头部添加一个元素,先创建,然后拷贝移动到deque头部 |
pop_front() | 移出deque头部的元素,对于空的deque不适用,移除后size-1,而capacity不变 |
insert() | 在指定的位置插入一个或多个元素,插入后size+1,capacity可能不变 |
erase() | 移出一个元素或一段元素,移除后size减小,capacity不变 |
clear() | 移出所有的元素,容器大小变为 0 |
swap() | 交换两个容器的所有元素/td> |
emplace() | 在指定的位置直接生成一个元素,大小+1 |
emplace_back() | 在deque尾部生成一个元素,由于其是在尾部直接生成而不是拷贝元素或移动,因此效率比push_back高 |
emplace_front() | 在deque头部生成一个元素,由于其是在头部直接生成而不是拷贝元素或移动,因此效率比push_front高 |
注意,deque没有data()函数,这是deque的底层实现决定的。
由于函数的定义与重载与vector十分类似,这里不再演示
deque的底层原理
deque的底层原理,是借助这样的一个结构实现的
![](https://img-blog.csdnimg.cn/8cbbcfd7b2114113a59448d1a9d1aca7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5piv5LiA5Y-q5bCP5YWU5YWU77yB,size_20,color_FFFFFF,t_70,g_se,x_16)
map是一个地址数组,存储着各个连续空间的首地址,通过这个map数组,deque 容器申请的这些分段的连续空间就能实现“整体连续”的效果。
list
双向链表容器,底层是以双向链表的形式实现的。因此,list 容器中的元素可以分散存储在内存空间里。
定义
类似的,list的创建也有两种方式:
1.
#include<list>
using namespace std;
list<int> L;
2.
#include<list>
std::list<int> L;
注意,这样定义的list容器,因为容器中没有元素,所以没有为其分配空间。当添加第一个元素(比如使用 push_back() 函数)时,list 会自动分配内存。
初始化
与vector类似的5种初始化方式
第一种方式,初始化成员列表:
list<int> v1{1,2,3,4,5};
第二种方式,指定元素个数(默认初始化为0)
list<int> v2(5);//5个0
第三种方式,指定元素个数并全部初始化为1
list<int> v3(5,1);//5个1
第四种方式,存储已经存在的list容器值或数组
list<int> a(v3); //5个1
list<int> b(v1.begin(),v1.begin()+3);//1 2 3
int arr[3] = {4,5,6};
list<int> c(arr,arr+3);//4 5 6
也跟vector一样在某些方面有限制
list<int> v;
for (auto it = v.begin();it != v.end();it++){
*it = 1;
cout << *it << ' ';
}
//不会报错,但是不会做到预想的结果,因为空的list的begin() == end()
成员函数
比起vector,array和deque,list的迭代器类型为双向迭代器,这决定了对于list的迭代器不能使用任何的比较运算符,+=、-=之类的一次跨越多步的运算符以及不能通过下标访问元素。但是其支持使用==和!=运算符
size() | 返回实际元素个数 |
max_size() | 返回元素个数的最大值。这通常是一个很大的数 |
resize() | 调整容器的大小 |
empty() | 返回list是否非空 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的list容器 |
back() | 返回容器中最后一个元素的直接应用,该函数同样不适用于空的list容器 |
assign(val) | 将val赋值给list中的每一个元素,相当于批量赋值,可以用于初始化 |
push_back() | 在list的尾部添加一个元素,先创建,然后拷贝移动到list末尾 |
pop_back() | 移出list尾部的元素,对于空的list不适用,移除后size-1,而capacity不变 |
push_front() | 在list的头部添加一个元素,先创建,然后拷贝移动到list头部 |
pop_front() | 移出list头部的元素,对于空的list不适用,移除后size-1,而capacity不变 |
insert() | 在指定的位置插入一个或多个元素,插入后size+1,capacity可能不变 |
erase() | 移出一个元素或一段元素,移除后size减小,capacity不变 |
clear() | 移出所有的元素,容器大小变为 0 |
swap() | 交换两个容器的所有元素 |
emplace() | 在指定的位置直接生成一个元素,大小+1 |
emplace_back() | 在list尾部生成一个元素,由于其是在尾部直接生成而不是拷贝元素或移动,因此效率比push_back高 |
emplace_front() | 在list头部生成一个元素,由于其是在头部直接生成而不是拷贝元素或移动,因此效率比push_front高 |
splice() | 将一个 list 容器中的元素插入到另一个容器的指定位置 |
remove(val) | 删除容器中所有等于 val 的元素 |
remove_if() | 删除容器中满足条件的元素 |
unique() | 删除容器中相邻的重复元素,只保留一个 |
merge() | 合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的,如果原本的两个list无序则报错 |
sort() | 通过更改容器中元素的位置,将它们进行排序 |
reverse() | 反转容器中元素的顺序 |
另外,由于list底层的实现机制的原因,对list容器进行插入、删除、结合等操作的时候不会导致原有的迭代器失效,只有删除会导致当前指向的迭代器失效。
部分list添加的函数举例:
void show(list<int> v) {
for (auto c : v) {
cout << c << ' ';
}
cout << endl;
}
int main() {
list<int> L{ 0,0,0,1,4,3 };
show(L);//0 0 0 1 4 3
L.remove(0);
show(L);//1 4 3
L.sort();
show(L);//1 3 4
list<int> L2{ 4,5,6 };
L.merge(L2);
show(L);//1 3 4 4 5 6
L.unique();
show(L);//1 3 4 5 6
L.reverse();
show(L);//6 5 4 3 1
}
insert、erase等函数的使用方法与上文一致,这里不再重复
但是对于一些新的方法这里给出使用形式
1.splice()
splice() 成员方法的作用对象是其它 list 容器,其功能是将其它 list 容器中的元素添加到当前 list 容器中指定位置处
void splice (iterator pos, list& l);将 l 容器中存储的所有元素全部移动当前 list 容器中 pos 指明的位置处。
void splice (iterator pos, list& l, iterator it);将 l 容器中 it 指向的元素移动到当前容器中 pos 指明的位置处
void splice (iterator pos, list& l, iterator first, iterator last);将 l 容器 [first, last) 范围内所有的元素移动到当前容器 pos 指明的位置处
注意,无论使用哪种形式,添加完成后l都为空
2.remove_if()
remove_if(lambda)该函数接受一个lambda表达式(实际上是一个函数),满足条件的都将被删除。
void show(list<int> v) {
for (auto c : v) {
cout << c << ' ';
}
cout << endl;
}
int main() {
list<int> L{ 0,0,0,1,4,3 };
list<int> L2{ 4,5,6 };
L.splice(L.begin(), L2);//4 5 6 0 0 0 1 4 3
show(L);
L.splice(L.end(), L2, L2.begin());//0 0 0 1 4 3 4
show(L);
L.splice(L.end(), L2, L2.begin(), L2.end());//0 0 0 1 4 3 4 5 6
show(L);
L.remove_if([&](int data) {return data <= 0; });//1 4 3
show(L);
}
list的底层原理
list的底层即双向链表
![](https://img-blog.csdnimg.cn/811147cf0d8042beb7c618153f5670dd.png)
forward_list
forward_list,采用单链表构建的一种stl数据结构
定义
类似的,forward_list的创建也有两种方式:
1.
#include<forward_list>
using namespace std;
forward_list<int> L;
2.
#include<forward_list>
std::forward_list<int> L;
注意,这样定义的forward_list容器,因为容器中没有元素,所以没有为其分配空间。当添加第一个元素(比如使用 push_back() 函数)时,forward_list 会自动分配内存。
初始化
与vector类似的5种初始化方式
第一种方式,初始化成员列表:
forward_list<int> v1{1,2,3,4,5};
第二种方式,指定元素个数(默认初始化为0)
forward_list<int> v2(5);//5个0
第三种方式,指定元素个数并全部初始化为1
forward_list<int> v3(5,1);//5个1
第四种方式,存储已经存在的forward_list容器值或数组
forward_list<int> a(v3); //5个1
forward_list<int> b(v1.begin(),v1.begin()+3);//1 2 3
int arr[3] = {4,5,6};
forward_list<int> c(arr,arr+3);//4 5 6
也跟vector一样在某些方面有限制
forward_list<int> v;
for (auto it = v.begin();it != v.end();it++){
*it = 1;
cout << *it << ' ';
}
//不会报错,但是不会做到预想的结果,因为空的forward_list的begin() == end()
成员函数
因为forward_list底层采用了单链表的形式,因此forward_list的迭代器为正向迭代器,因此其对应的前面八个迭代器函数中带r的都不存在
before_begin() | 返回指向容器中第一个元素之前的位置的迭代器 |
cbefore_begin() | 返回指向容器中第一个元素之前的位置的迭代器,不能用于修改元素 |
max_size() | 返回元素个数的最大值。这通常是一个很大的数 |
resize() | 调整容器的大小 |
empty() | 返回list是否非空 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的list容器 |
assign(val) | 将val赋值给list中的每一个元素,相当于批量赋值,可以用于初始化 |
push_front() | 在list的头部添加一个元素,先创建,然后拷贝移动到list头部 |
emplace_front() | 在list头部生成一个元素,由于其是在头部直接生成而不是拷贝元素或移动,因此效率比push_front高 |
pop_front() | 移出list头部的元素,对于空的list不适用 |
insert_after() | 在指定的位置插入一个元素,返回一个指向新元素的迭代器 |
emplace_after()/td> | 在指定的位置插入一个元素,效率高于insert_after() |
erase_after() | 删除容器中某个指定位置或区域内的所有元素 |
clear() | 移出所有的元素,容器大小变为 0 |
swap() | 交换两个容器的所有元素/td> |
splice_after() | 将某个 forward_list 容器中指定位置或区域内的元素插入到另一个容器的指定位置之后 |
remove(val) | 删除容器中所有等于 val 的元素 |
remove_if() | 删除容器中满足条件的元素 |
unique() | 删除容器中相邻的重复元素,只保留一个 |
merge() | 合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的,如果原本的两个list无序则报错 |
sort() | 通过更改容器中元素的位置,将它们进行排序 |
reverse() | 反转容器中元素的顺序 |
注意没有size()函数
forward_list的底层原理
forward_list 使用的是单链表
![](https://img-blog.csdnimg.cn/a32c2f0fd9934c3a8a08c982e988b36e.png)