本文是在阅读SGI STL v3.3源码中关于algorithm
部分,遇到的一些问题及有意思的点。
至此,STL六大件告一段落。(源码中,还有一些实现相应辅助功能的其他文件在此假装没有)。
algorithm
从实现角度看,STL算法实质上也是一种模板类。
STL中所有的算法前两个参数都是一对迭代器,所包含的元素都是左闭右开
最后一个可选参数一般都是自定义规则(仿函数传入点),鉴于仿函数( _Compare __comp
)传入进来只是比较规则位置发生变化,下文中以默认带有仿函数的为准。
max/min/swap略过
此外,在众多的函数中有着如下规律:
xxx
和xxx_if
xxx
一般为对值为value
的元素进行操作
xxx_if
则是对value
满足一定条件(__pred
)的元素进行操作
xxx
和 xxx_n
xxx
一般前两个参数为iter first
和iter last
表示对一个区间内进行操作
xxx_n
则是iter first
和size_t n
是以first
为首的n
个元素进行操作(也是一个区间)
xxx
和xxx_copy
xxx
一般是对原数组进行操作。
xxx_copy
是将操作的结果保存到中。
accumulate
将的值累加到init
上。(init
在原基础上增加区间和。)
1 2 3 4 5 6 7 8 9 10
| template <class _InputIterator, class _Tp, class _BinaryOperation> _Tp accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOperation __binary_op) { for ( ; __first != __last; ++__first) __init = __binary_op(__init, *__first); return __init; }
|
inner_product
我们知道两个向量的内积公式:已知两个向量:
两个向量的内积:
两个数组的内积公式依然,数组中元素的个数类比向量的维度。
将与两个区间做内积,并将结果累加到init
。
由于第二区间只给了首迭代器(first2
),要保证容器中的元素个数充足。
1 2 3 4 5 6 7 8 9 10 11 12
| template <class _InputIterator1, class _InputIterator2, class _Tp, class _BinaryOperation1, class _BinaryOperation2> _Tp inner_product(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2) { for ( ; __first1 != __last1; ++__first1, ++__first2) __init = __binary_op1(__init, __binary_op2(*__first1, *__first2)); return __init; }
|
__binary_op1
— 累加方式
__binary_op2
— 内积方式
partial_sum
计算范围的子范围中元素的部分和,并写入到始于 result 的范围
假设表示数组,由result开始的数组。则该函数实现的功能是。
类似于数列的
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
| template <class _InputIterator, class _OutputIterator, class _Tp, class _BinaryOperation> _OutputIterator __partial_sum(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Tp*, _BinaryOperation __binary_op) { _Tp __value = *__first; while (++__first != __last) { __value = __binary_op(__value, *__first); *++__result = __value; } return ++__result; }
template <class _InputIterator, class _OutputIterator, class _BinaryOperation> _OutputIterator partial_sum(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOperation __binary_op) { if (__first == __last) return __result; *__result = *__first; return __partial_sum(__first, __last, __result, __VALUE_TYPE(__first), __binary_op); }
|
adjacent_difference
计算范围的相邻元素的差值,并写入到始于 result 的范围。
假设表示数组,由result开始的数组。则该函数实现的功能是,特例
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
| template <class _InputIterator, class _OutputIterator, class _Tp, class _BinaryOperation> _OutputIterator __adjacent_difference(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Tp*, _BinaryOperation __binary_op) { _Tp __value = *__first; while (++__first != __last) { _Tp __tmp = *__first; *++__result = __binary_op(__tmp, __value); __value = __tmp; } return ++__result; }
template <class _InputIterator, class _OutputIterator, class _BinaryOperation> _OutputIterator adjacent_difference(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOperation __binary_op) { if (__first == __last) return __result; *__result = *__first; return __adjacent_difference(__first, __last, __result, __VALUE_TYPE(__first), __binary_op); }
|
power
快速幂求。
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 31 32
| template <class _Tp, class _Integer, class _MonoidOperation> inline _Tp power(_Tp __x, _Integer __n, _MonoidOperation __opr) { return __power(__x, __n, __opr); }
template <class _Tp, class _Integer, class _MonoidOperation> _Tp __power(_Tp __x, _Integer __n, _MonoidOperation __opr) { if (__n == 0) return identity_element(__opr); else { while ((__n & 1) == 0) { __n >>= 1; __x = __opr(__x, __x); }
_Tp __result = __x; __n >>= 1; while (__n != 0) { __x = __opr(__x, __x); if ((__n & 1) != 0) __result = __opr(__result, __x); __n >>= 1; } return __result; } }
|
iota
将元素的值赋给
1 2 3 4 5 6
| template <class _ForwardIter, class _Tp> void iota(_ForwardIter __first, _ForwardIter __last, _Tp __value) { while (__first != __last) *__first++ = __value++; }
|
iter_swap
交换所指向的元素。(指向的内存不变)
以下几个copy/fill函数均有针对字符串的重载,调用memset
去赋值。
由于实现的功能是赋值,也没有额外增加运算规则的重载。
copy
正向拷贝(从前往后读取并赋值)。有random_access_iterator_tag
、input_iterator_tag
、__copy_trivial
等多个版本所实现的功能均为将区域的内容拷贝至内。
copy_backward
反向拷贝(从后往前读取并赋值)。同样有多个重载版本,但实现的功能一样。
将区域的内容拷贝至内。
copy_n
将拷贝给
fill
将的值赋为value
fill_n
将的值赋为value
mismatch
将与中对应位置的元素进行对比。返回 值不相等时的两个迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13
| template <class _InputIter1, class _InputIter2, class _BinaryPredicate> pair<_InputIter1, _InputIter2> mismatch(_InputIter1 __first1, _InputIter1 __last1, _InputIter2 __first2, _BinaryPredicate __binary_pred) { while (__first1 != __last1 && __binary_pred(*__first1, *__first2)) { ++__first1; ++__first2; } return pair<_InputIter1, _InputIter2>(__first1, __first2); }
|
equal
对比与对应位置的元素是否相等,完全相等返回true
lexicographical_compare
以字典序对比与。区间1小于区间2则返回true
1 2 3 4 5 6 7 8 9 10 11 12 13
| template <class _InputIter1, class _InputIter2, class _Compare> bool lexicographical_compare(_InputIter1 __first1, _InputIter1 __last1, _InputIter2 __first2, _InputIter2 __last2, _Compare __comp) { for ( ; __first1 != __last1 && __first2 != __last2 ; ++__first1, ++__first2) { if (__comp(*__first1, *__first2)) return true; if (__comp(*__first2, *__first1)) return false; } return __first1 == __last1 && __first2 != __last2; }
|
一个辅助函数,用于寻找3个元素中的最小值。
- 可传入第四个参数
__comp
,用于更改元素间的比对规则。
for_each
遍历。遍历区间,并对每个元素执行_Function __f
以下 find/count函数针对iterator_category
不同
分为input_iterator_tag
和random_access_iterator_tag
两个版本
find
在中查找第一个值为val
的位置。
find_if
在中查找第一个值满足__pred
条件的位置。
adjacent_find
在中查找 2 个连续相等的元素。如果能找到返回前一个元素位置的迭代器。
允许自定义判断规则__binary_pred
count
判断中val
出现的次数,并将值加在n
上。
count_if
判断中元素满足__pred
条件的个数,并将值加在n
上。
search
在中寻找第一个与相等(或满足__predicate
条件)的子数组,返回首个元素的位置。
search_n
在中寻找第一次连续出现__count
个元素值等于__val
(或满足__binary_pred
条件的__val
)的位置。(返回首元素位置)
swap_ranges
调用[iter_swap](# iter_swap)实现,互换与区间元素(交换所存的值)
1 2 3 4 5 6 7
| template <class _ForwardIter1, class _ForwardIter2> _ForwardIter2 swap_ranges(_ForwardIter1 __first1, _ForwardIter1 __last1, _ForwardIter2 __first2) { for ( ; __first1 != __last1; ++__first1, ++__first2) iter_swap(__first1, __first2); return __first2; }
|
将函数__opr
(可一元和二元)应用到序列的元素上,并将这个函数返回的值保存到另一个序列中。
当传入二元仿函数时,需要额外传入一个迭代器first2
,所实现的功能是:将与进行__binary_op
运算并将结果存储在
transform与for_each的区别
- for_each所调用的仿函数没有返回值,且只能在原位置上修改。
- transform所调用的函数必须有返回值(要依次赋值给另一区间),原位置元素不受影响。
replace
将中值等于__old_value
的元素(满足pred
条件的元素)替换为__new_value
replace_copy(_if)
replace
中的替换是在原位置上进行,该函数是以原数组为基础进行操作,并将结果存在新位置。
将中的值赋值到中,并将其中等于__old_value
的元素(满足pred
条件的元素,增加_if
)替换为__new_value
。
generate(_n)
为(或)中元素赋值为__gen
。__gen
要求为lambda表达式。
generate与for_each区别
1 2 3 4 5 6
| for ( ; __first != __last; ++__first) *__first = __gen();
for ( ; __first != __last; ++__first) __f(*__first);
|
因为函数调用的形式不同,进而对输入的要求也不同。for_each传入的是一个仿函数,而generate传入的是lambda表达式。
remove(_copy) (_if)
值为__value
可以替换成满足__pred
条件(函数名增加_if
)
remove
在中删除掉值为__value
的元素(后面元素前移实现覆盖。)
为实现后面元素前移的覆盖,使用的是remove_copy
函数
remove_copy
在中删除掉值为__value
的元素并将结果保存到以__result
为首地址的容器中。
unique_copy
将,拷贝到中,并将连续相等元素删除后者。
(相邻且满足__binary_pred
条件的后者)
unique
对中连续相等的元素删除后者(相邻且满足__binary_pred
条件的后者)
reverse
翻转区间内的元素。(从两端向中间,依次交换所存储的值)
1 2 3 4 5 6 7 8 9 10 11
| template <class _BidirectionalIter> inline void reverse(_BidirectionalIter __first, _BidirectionalIter __last) { __reverse(__first, __last, __ITERATOR_CATEGORY(__first)); }
template <class _RandomAccessIter> void __reverse(_RandomAccessIter __first, _RandomAccessIter __last, random_access_iterator_tag) { while (__first < __last) iter_swap(__first++, --__last); }
|
reverse_copy
与先reverse
后拷贝实现上有些差别
逆序读取区间的值,并写入中
rotate
将中的元素以middle
断开。先存放再存放。返回,开始时first指向的元素现在的位置。(底层实现上疯狂转轮,看不懂)
rotate_copy
与先rotate
后拷贝实现上有些差别
先调用copy(__middle, __last, __result)
将的元素存放在以result
开始的空间,然后利用copy返回值iter
(result开始的数组下一可存放位置)再次调用copy(__first, __middle,iter)
将中的元素拷贝到剩余部分。
下述扰乱函数 可加入一个生成随机数的仿函数__rand
random_shuffle
将中的元素随机扰乱。(随机洗牌)有种可能。
random_sample_n
将中的个元素随机的复制到中。(原数组中每个位置的元素仅能出现一次。)
random_sample
将中的个元素随机的复制到中。(原数组中每个位置的元素仅能出现一次。)
以 为参数调用random_sample_n
partition
以__pred
为规则对中的元素进行分组(不保证顺序)满足条件的移动至前半部分。
stable_partition
同样执行partition
相关功能,但保证各自分组内元素的相对顺序。
sort
对进行升序排序。所使用的底层排序算法为插入排序、堆排序(调用partial_sort
函数,底层堆排序)。
值相同的元素再排序后,不保证其相对位置。
stable_sort
对进行升序排序。底层排序算法 归并排序。值相同会保证相对位置。
partial_sort
在中选出middle - first
个最小元素存放在中。
partial_sort_copy
在中选出个最小元素,存放在中
nth_element
在中找到第n小的元素,并将其移动到第n个位置()
lower_bound
在中寻找第一个不小于val
的元素。(__comp
重载比较规则)
upper_bound
在中寻找第一个大于val
的元素。(__comp
重载比较规则)
equal_range
在中寻找等于val
的所有元素。(__comp
重载比较规则)
binary_search
在中二分查找是否存在元素val
merge
将与归并排序后存在中
需要注意与均为升序。
inplace_merge
同样是归并排序。所不同的是该函数是在一个数组中间选定一个中间值,分成前后两个子数组,两个子数组进行归并排序,最终结果存在原数组中。由于涉及到元素换位置问题,故和merge有些出入。
和进行排序。
includes
判断是否存在于中,返回T/F
set_union
实现两个有序集合和的并集操作,并将结果(仍有序)保存在以result
开始的数组中。
与merge
不同点在于,set_union
遇到相同元素会去重。
set_intersection
求两个集合和中相同的元素(或comp(1,2)
与comp(2,1)
均不满足的)。并将结果(仍有序)保存在以result
开始的数组中。
set_difference
求在不在中的元素。并将结果(仍有序)保存在以result
开始的数组中。
set_symmetric_difference
与不重复的元素。
max_element
返回中元素值最大的元素的迭代器(重定义比较规则comp
)
min_element
返回中元素值最小的元素的迭代器(重定义比较规则comp
)
next_permutation
由中所有元素组成的排列中,按照从小到大排序后,当前的下一个排列。
prev_permutation
由中所有元素组成的排列中,按照从小到大排序后,当前的上一个排列。
find_first_of
寻找中的(任意)字符在中出现最早的位置。返回该位置的下一位置。(或)中满足__comp
条件的元素。
中每读取一个元素便与中所有元素比对一次。
find_end
在中寻找最后一个与相等(或满足__predicate
条件)的子数组,返回首个元素的位置。
is_sorted
是否有序(或 任意相邻元素满足__comp
关系)