其它算法
现在总结一下我们学习了哪些 STL 算法。首先,我们以 rg::sort
和 rg::copy
这两个常用的算法作为引入,了解了 STL(主要是 STLv2)的基本使用方法。其次,我将话题转向函数式思想的常用方法:用作筛选的 rg::copy_if
和 std::views::filter
、用作转换的 rg::transform
和 std::views::transform
,以及用作归约的 std::accumulate
和 std::reduce
。此外,还有如 std::views::take
、输入输出迭代器/视图等辅助工具帮我们写出更好的代码。
但 STL 算法实在是太多了,我也不希望在这里把它们全部讲完。当初我的老师直接把 STLv1 的所有算法函数念了一遍,两三个小时学生啥也记不住。这样做是没有太多意义的。
首先,我按照通常的习惯把 STL 算法分成若干类:
- 检查式的算法:它们检查一个范围内的元素,不修改它们也不会生成新的元素。
- 生成元素的算法:它们会生成一些新的元素;调用的时候一般需要提供目的地迭代器。
- 修改元素的算法:它们会将范围内的元素值修改掉。这其中又包括:
- 简单算法:如覆盖、反转等;
- 删除算法:如
rg::remove
rg::unique
等。它们一般需要配合容器的erase
方法使用。 - 高级算法:排序、排列等。
- 在已排序范围上的算法:主要包括二分搜索和集合运算。严格上它们属于修改元素的算法,但它们自成体系,故单独列出。
- 惰性算法:即视图和对应的范围适配器。
CppReference 里列出了所有的 STL 算法。上面的分类完全是个人意见;如果你有更好的看法请告诉我。
接下来我再介绍一些常用的算法。
删除算法
之前介绍筛选算法时,提到了筛选出的元素应该如何存放的问题。当时给出了两个方案:一是 rg::copy_if
,将元素选择性地复制到新的地方。这对应了刚刚分类里的“生成元素的算法”。二是使用范围适配器,即刚刚分类里的“惰性算法”。但还有第三种可能:直接原地修改原来容器里的元素——也就是“修改元素的算法”。
简单算法
简单算法指一句话就能带过的算法
rg::fill
将一个范围填充为单个元素。使用方法如rg::fill(a, 0)
。rg::reverse
将一个双向范围内的元素反转。使用方法如rg::reverse(a)
。rg::shuffle
将随机访问范围内的元素随机重排(洗牌)。使用方法如rg::shuffle(a, g)
;其中g
是伪随机数生成引擎。rg::rotate
将前向范围内的元素 旋转。所谓旋转是指,将每个元素都向左平移一定长度,然后让头部元素移到尾部。使用方法如rg::rotate(a, a.begin() + 4)
;第二个参数是迭代器,指向旋转后的首个元素。
检查式的算法
rg::min
rg::max
rg::any_of
rg::all_of
rg::none_of
rg::find
rg::find_if
其它……
还有很多很多没有提到的 STL 算法,但它们在程序设计中用到的不多。如果感兴趣的话可以自行学习。
其实已排序范围上的算法在算法竞赛中用得比较多。