不再造轮子,攻略 STL 中的所有算法
- STL 算法概观
- 数值算法
- 基本算法
-
- 3.1 equal, fill, fill_n, iter_swap, lexicographical_compare, max,min,mismatch, swap
- 3.2 copy --强化效率无所不用其极
- 3.3 copy_backward 反向拷贝
- 3.4 set 相关算法
- 3.4 heap 算法
- 3.5 单纯的数据处理算法
-
- adjacent_find : 找出满足条件的相邻元素
- count 与 count_if : 统计指定元素的个数
- find 和 find_if :查找第一个满足条件的元素
- find_end: 在序列1中查找序列2的最后一次出现点
- for_each : 遍历每一个元素,将仿函数 f 施加其每一个元素
- includes: s2 是否被包含于 s1 中
- max_element/min_element: 求序列中的最大/小元素
- merge 合并两个有序区间
- partition :分割排列元素,将满足特定条件的元素放在区间前半段
- remove 移除元素(但不是删除)
- replace : 将区间内的所有 old_value 全部用 new_value 取代
STL 算法概观
1.1 STL 算法总览
- 质变:指会改变其操作对象的内容
- *表示不在 STL 标准规格的 SGI 专属算法
- if in-place 指在同一区间操作
1.2 质变算法 mutating algorithm
STL 算法都作用在迭代器【first, last) 所标识的区间上。
质变算法: 在运算过程中会更改区间内(迭代器所指)的元素内容。
例如: 拷贝,交换,替换,填充,删除, 排列组合,分割, 随机重排,排序等算法,都属于该类。
若将该类算法运用到一个常数区间上,则编译器会给予一大堆错误 信息。
#include "main.h"
2 using std::vector;
3 int main()
4 {
5 vector<int> ivec{
1,2,3,4,5};
6 sort(ivec.cbegin(), ivec.cend());
7 return 0;
8 }
9
1.3 非质变算法 nomutating algorithms
非质变算法: 在运算过程中不会改变区间内元素的内容
诸如: 查找,匹配,计数,遍历,比较等算法
如果在这些算法添加一个会改变内容的仿函数, 元素当然会被改变。
1.4 STL 算法的一般形式
- 所有泛型算法的前两个参数都为一对迭代器,且位前闭后开区间【first, last)
- 区间必须满足first 累加操作的反复运用,能到达 last,因此需要保证算法能接收的最低程度的迭代器类型。
- 设置特定操作: STL 算法中大多支持多个版本,拥有自己的缺省行为, 通过外界传递仿函数(functor),以便采用其他策略。 附从 _if 的算法如 find_if 也是一样可以传递仿函数进行对比行为。
- 具有拷贝版本的算法: 在质变算法中,除了就地修改外,还提供了 copy(另行版本)将修改后的区间序列拷贝到另外的地方,如: replace_copy
数值算法都实现与 numeric 中,其他都实现在 algorithm 中
数值算法
数值算法统一定义在 numeric 中, 我们来介绍如下几种:
int ia[5] = {
1, 2, 3, 4, 5};
6 vector<int> iv(ia, ia+5);
7 cout << accumulate(iv.begin(), iv.end(), 0) << endl;
// 15
8 cout << accumulate(iv.begin(), iv.end(), 0, minus<int>()) << endl;
// -13
9 cout << inner_product(iv.begin(), iv.end(), iv.begin(),10) << endl;
// 10 + 1*1 + 2*2 .。。。
10 cout << inner_product(iv.begin(), iv.end(), iv.begin(), 10, minus<int>(), plus<int>());
// 10 - (1+1) - (2+2) -(3+3)
11
12 ostream_iterator<int> oite(cout, " ");
13 partial_sum(iv.begin(), iv.end(), oite) ;
// 1 3 6 10 15
14 partial_sum(iv.begin(), iv.end(), oite, minus<int>());
15 // 1 -1 - 4 -8 -13
16 adjacent_difference(iv.begin(), iv.end(), oite);
// 1 1 1 1 1
17 adjacent_difference(iv.begin(), iv.end(), oite, plus<int>());
18 // 1 3 5 7 9
2.1 accumulate 元素累计算法
- 将元素按二元仿函数的规则累计操作的结果相加到 init 上。
- 默认是 1+2+3 ,若位 minus则, 1-2-3.。。
1 // 版本1
2 template <class InputIterator, class T>
3 T accumulate(InputIterator first, InputIterator last, T init) {
4 for(; first != last; ++first)
5 init += *first;
6 return init;
7 }
8 //版本2
9 template <class InputIterator, class T, class BinaryOperation>
10 T accumulate(InputIterator first, InputIterator last, T init,
11 BinaryOperation binary_op) {
12 for(; first != last; ++first)
13 init = binary_op(init, *first);
14 return init;
15 }
2.2 adjacent_difference 相邻元素之间的差额算法
- 用于计算 【first, last)中相邻元素的差额。
- 将 *first 赋值给 *result ,并针对 [first+1,last) 内的每个迭代器 i, 将 *i - *(i-1)的值赋值给 *(result + (i - first))
- 提供二元仿函数的版本是 将 binary_op(*i, *(i-1)) 的运算结果赋值给 *(result+i-first)
18 template <class InputIterator, class OutputIterator>
19 OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result) {
20 if(first == last)
21 return result;
22 *result = *first;
23 typedef typename std::iterator_traits<InputIterator>::value_type value_type;
24 value_type value = *first;
25 while(++first != last) {
26 value_type tmp = *first; //原地操作时会造成问题,因此需要临时量
27 *++result = tmp - value;
28 value = tmp;
29 }
30 return ++result;
31 }
32 template <class InputIterator, class OutputIterator, class BinaryOperation>
33 OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op) {
34 if(first == last)
35 return result;
36 *result = *first;
37 using value_type = typename std::iterator_traits<InputIterator>::value_type;
38 value_type val = *first;
39 while(++first != last) {
40 value_type tmp = *first;
41 *++result = tmp - val;
42 val = tmp;
43 }
44 return ++result;
45 }
2.3 inner_product 求两个区间的一般内积(对应元素相乘之后累加一起)
- 算法 inner_product 能够计算 【first1, last1) 和 【first2, first2+ (last1 - first1))的一般内积,
先将初始结果初始化位 init, 之后针对 【first1 , last1)的每一个迭代器 i, 从头至尾依序执行
result = result + (*i) * *(first2 + (i - first1))
- 需要提供初始值 init ,为了能在两个区间都为空的情况下有一个明确的值
- 可提供仿函数取代 operator+ 和 operator*,
先将初始结果初始化为 init, 之后针对【first1, last1) 的每一个迭代器i, 从头到尾依序执行:
result = bindary_op1(result, bindary_op2(*i, *(first2 +(i-first1))))
47 template<class InputIterator1, class InputIterator2, class T>
48 T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init) {
49 for(; first1 != last1; ++first1, ++first2) {
50 init += *first1 * *first2;
51 }
52 return init;
53 }
54
55 template<class InputIterator1,class InputIterator2, cl