C++ STL容器—— forward_list 成员函数用法详解

C++ STL容器—— forward_list 成员函数用法详解

写在前面:近期正在重新学习C++的STL容器,因此准备将STL函数的用法详细记录一下,主要介绍一些基本成员函数的用法, 外加实际的例子,并不涉及原理。其实了解这些函数最好的方法还是需要自己上手操作一下.
写的不好, 请大神手下留情.

下面说的 “运行之后” 表示: 运行上个语句之后的结果.
一行如果说的太长的话, 就得拖动下面的进度条才能看到后面的内容, 非常麻烦
因此将一段话分成了多行,就像现在这种形式

目录

        • C++ STL容器—— forward_list 成员函数用法详解
          • 简介
          • 构造函数
          • 迭代器
          • 常用函数
          • assign(赋值函数)
          • 容量与长度函数
          • insert_after(插入函数)
          • emplace系列(插入函数)
          • merge(合并函数)
          • splice_after(拼接函数)
          • erase_after(删除函数)
          • remove系列(移除函数)
          • unique(排重函数)
          • sort(排序函数)
简介

需要头文件:# include < forward_list>
动态单向链表, 其实就是将 list 容器的尾部封住, 让你不能直接的访问和操作, 点击前往: list 成员函数用法详解

与 list 容器的区别
list 容器两端都可以访问和操作, 给我的感觉更像是一个不能随机访问的 vector 容器
forward_list 只能在头部进行操作, 其实也可以通过 insert 成员函数在尾部插入, 他的一些函数更有链表的感觉.

构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
forward_list <int> fl, fl1;
//定义 int 类型的链表

forward_list <char> flch;
//定义 char 类型的链表

forward_list <string> flstr;
//定义 string 类型的链表

forward_list <int> fl2(10);
//定义拥有 10 个空间的链表, 每个元素都为 0

forward_list <int> fl3(5, 30);
//定义拥有 5 个空间的链表,并全部初始化为 30

forward_list <int> fl4 = { 1,2,3,4 };
//定义拥有 4 个空间的链表, 初始化为[1,2,3,4]

forward_list <int> fl5{ 1,2,3,4 };
//同上

forward_list <int> fl6(fl);
//将 fl 的所有元素复制给 fl6

forward_list <int> fl7(fl.begin(), fl.end());
//将范围内的元素复制给 l7

//不能使用下标 [] 随机访问
迭代器

包括: begin、end、cbegin、cend、before_begin、cbefore_begin
注意区别.
使用方法:

1
auto it=fl.begin(); //相当于指针,用 *it 访问

fl.begin(); 返回指向fl第一个元素的迭代器
fl.end(); 返回指向fl最后一个元素下一个元素的迭代器
fl.cbegin(); 返回指向fl第一个元素的迭代器, 类型为const
fl.before_begin(); 返回指向第一个元素之前的迭代器
例: 使用正向遍历 fl 数组

1
2
3
4
5
6
7
forward_list <int> fl{ 1,2,3,4,5,6 };
for (auto it = fl.begin(); it != fl.end(); it++) {
    //注意这里是不等于end, 而不是小于end
    cout << *it <<' ';
}
输出结果为:
1 2 3 4 5 6

遍历
fl.begin(),fl.begin()+1,···,fl.end()-1,fl.end()
begin和cbegin的区别
可以通过fl.begin()修改 fl 的值 (具体可不可以需要看 fl )
不能通过fl.cbegin()修改 fl 的值

常用函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fl.push_front(4);
//在头部插入元素 4, vector 没有这个函数
//例:fl={1,2,3}
//运行之后, fl={4,1,2,3}

fl.pop_front();
//删除第一个元素, vector 没有这个函数
//例:fl={1,2,3,4}
//运行之后, fl={2,3,4}

fl.front();
//返回 fl 的第一个元素
//例:fl={1,2,3,4}
//fl.front()就等于 1
   
fl.clear();
//清空 fl 容器

fl.empty();
//返回 fl 容器是否为空, 空的返回 true, 非空返回 false

fl.swap(fl1);
//将 fl 与 fl1 交换
//例:fl={1,2,3,4}, fl1={5,6,7}
//运行之后, fl={5,6,7}, fl1={1,2,3,4}

fl.reverse();
//将容器的所有元素进行翻转
//例:fl={1,2,3,4}
//运行之后, fl={4,3,2,1}
assign(赋值函数)
1
2
3
4
5
6
7
8
9
fl.assign(2, 3);
//将 2 个 3 赋值给 fl
//例:fl={5,6,7}
//运行之后 fl={3,3}

fl.assign(fl1.begin(), fl1.end());
//将迭代器指向的字符串赋值给 fl
//例:fl={5,6,7}, fl1={1,2,3,4}
//运行之后 fl={1,2,3,4}

容量与长度函数

这一部分, 有点绕.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fl.max_size();
//返回 fl 最多能保存元素的个数
//返回一个数字, 根据编译环境的不同, 这个数字也不同.

fl.resize(3);
//设置 fl 的 size
//例:fl={1,2,3,4,5,6}
//运行之后 fl={1,2,3}, 如果尺寸变小,多余的部分截掉
//例:fl={1,2}
//运行之后 fl={1,2,0}, 如果尺寸变大,新空间用 0 代替
我也不太清楚为什么forward_list 容器没有 size 这个成员函数
既然 size 都没有, 为什么会有 resize, 反正就是很迷

fl.resize(3, 2);
//设置 fl 的 size,如果尺寸变大,新空间全部用 2 代替
//例: fl={1,3}
//运行之后 fl={1,3,2}
insert_after(插入函数)

返回指向插入位置的迭代器(即: 第一个参数的下一个位置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fl.insert_after(fl.begin(), 3);
//在指向位置的后面插入元素 3
//例: fl={1,2}
//运行之后 fl={1,3,2}

fl.insert_after(fl.begin(), 2, 3);
//在指向位置的后面插入 2 个元素 3
//例: fl={1,2}
//运行之后 fl={1,3,3,2}

fl.insert_after(fl.begin(), fl1.begin(), fl1.end());
//在指向位置的后面插入 fl1 范围内的元素
//例: fl={1,2}, fl1={5,6,7},
//运行之后 fl={1,5,6,7,2}
emplace系列(插入函数)

emplace_front 返回空, emplace_after返回执行插入位置的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
fl.emplace_front();
//在容器的头部插入一个元素, 默认为 0
//例: fl={1,2}
//运行之后 fl={0,1,2}

fl.emplace_front(5);//在容器的头部插入一个元素 5
//例: fl={1,2}
//运行之后 fl={5,1,2}

fl.emplace_after(fl.begin(), 5);
//在指向位置的后面插入元素 5
//例: fl={1,2}
//运行之后 fl={1,5,2}

emplace / push_front 和 insert的区别

  1. 原理上
    emplace 是直接将插入的内容放进容器里面, 不需要生成对象
    push_front / insert 是先生成对象, 然后将对象的内容复制到容器里面
  2. 功能上
    emplace / push_front 只能插入一个元素
    insert 可以插入多个元素
  3. 性能上
    emplace的速度要更快一点
merge(合并函数)

合并两个已经排序的链表, 合并之前两个链表必须有序, 而且顺序相同, 按照同样的顺序进行合并, 合并之后清空第二个容器(fl1).

1
2
3
4
5
6
7
8
9
10
11
12
fl.merge(fl1);
//将 fl1 的内容合并到到 fl 里, 默认升序
//例: fl={1,3,5}, fl1={2,4,6}
//执行之后, fl={1,2,3,4,5,6}, fl1={};

fl.merge(fl1, greater <int>());
//将 fl1 的内容按照降序合并到到 fl 里
//例: fl={5,3,1}, fl1={6,4,2}
//执行之后, fl={6,5,4,3,2,1}, fl1={};

fl.merge(fl1, cmp);
//将 fl1 的内容按照自定义依据合并到到 fl 里
splice_after(拼接函数)

将第二个容器 (fl1) 的元素插入到第一个容器 (fl) 迭代器指向的下一个位置, 同时删除 fl1 中插入到 fl 的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fl.splice_after(fl.begin(), fl1);
//将 fl1 所有元素插入到 fl 迭代器指向位置的后面
//例: fl={1,2}, fl1={5,6,7},
//运行之后 fl={1,5,6,7,2}, fl1={};

fl.splice_after(fl.begin(), fl1, fl1.begin());
//将 fl1 迭代器指向的元素插入到 fl 迭代器指向位置的后面
//例: fl={1,3,5}, fl1={2,4,6}
//执行之后, fl={1,2,3,5}, fl1={4,6};

fl.splice_after(fl.begin(), fl1, fl1.begin(),fl1.end());
//将 fl1 指向的元素插入到 fl 迭代器指向位置的后面
//例: fl={1,2}, fl1={5,6,7},
//运行之后 fl={1,5,6,7,2}, fl1={};

insert / merge / splice 三个插入函数的区别
a.函数名(b)
将容器 b 的内容插入到容器 a 中

insert 函数就是正常的将容器 b 的内容复制插入到容器 a 中
merge 函数在使用之前两个容器必须具有相同的顺序(升序/降序/自定义的顺序), 是将容器 b 的内容按照一定的顺序移动插入到容器 a 中, 会将容器 b 中插入的内容删除
splice 函数是将容器 b 的内容移动插入到容器 a 中, 会将容器 b 中插入的内容删除

erase_after(删除函数)

返回一个迭代器,该迭代器指向被删除元素后面的元素(这个是重点)

1
2
3
4
5
6
7
8
9
10
fl.erase_after(fl.begin());
//删除指向位置的下一个元素
//删除位置上的元素
//例: fl={1,2,3}
//运行之后 fl={1,3}, 返回指向元素 3 的迭代器

fl.erase_after(fl.begin(), fl.end());
//删除范围内的元素(保留范围内的第一个元素)
//例: fl={1,2,3}
//运行之后 fl={1}
remove系列(移除函数)

通过特定条件查找到之后删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fl.remove(3);
//将容器里所有值为 3 的元素删除
//例: fl={1,2,3,3,4,3,3}
//运行之后 fl={1,2,4}

fl.remove_if([](int a) { return a > 3; });
//将大于 3 的数字全部删除
//例: fl={1,2,3,3,4,4,5}
//运行之后 fl={1,2,3,3}

fl.remove_if(cmp);//将符合 cmp 条件的元素删除
bool cmp(int a) {
// 10~100 返回 false, 其余返回 true
//其实就是删除10~100之外的数
    return a < 10 || a>100;
}
//例: fl={1,2,10,50,60,100,111}
//运行之后 fl={10,50,60,100}
unique(排重函数)
1
2
3
4
fl.unique();
//删除容器中相邻的相同元素(会留一个)
//例: fl={1,2,3,3,3,4,3,3,6}
//运行之后 fl={1,2,3,4,3,6}

erase / remove / unique 三个删除函数的区别
erase 函数是通过迭代器查找到元素之后, 进行删除
remove 函数是通过 特定条件 查到元素之后, 进行删除
unique 函数只将相邻的相同元素删除, 没有达到真正排重的效果

sort(排序函数)

因为 list 不能随机访问, sort 函数不能使用, 因此提出一个 sort成员函数, 作用和效果我认为是差不多的.

1
2
3
4
5
6
7
8
9
10
11
12
fl.sort();
//升序排序
//例: fl={1,2,3,5,4,1,3}
//运行之后 fl={1,1,2,3,3,4,5}

l.sort(greater<int>());
//降序排序
//例: l={1,2,3,5,4,1,3}
//运行之后 l={5,4,3,3,2,1,1}

l.sort(cmp);
//自定义排序依据 cmp

sort 和 unique 函数结合
正常来说是不会用到 unique 函数的, 他一般和 sort 成员函数配套使用, 达到将容器中相同的多余元素删除的效果(真正意义上的排重)
例如:

1
2
3
4
5
6
fl={2,5,1,6,1,3,2,4,1,5,6};
直接执行 unique 函数是不能真正做到排重的
只有先进行 sort 排序, 再执行 unique 函数, 才能达到要求
fl.sort();
fl.unique();
执行之后, fl={1,2,3,4,5,6}