SGISTL源码探究-stl_numeric.h中的数值算法
2017-09-20 16:03
309 查看
前言
上一小节中,我们对stl中的算法部分做了一个大致的说明。本小节我们将进入到其中关于数值算法的部分,都在
stl_numeric.h文件中。废话不多说,直接看源码吧。
stl_numeric
accumulate
注意该算法要求了迭代器的类型至少是InputIterator类型,如果是
OutputIterator类型,肯定是不行的。
用于计算元素总和,init加上[first, last)范围内的元素之和。
template <class InputIterator, class T> T accumulate(InputIterator first, InputIterator last, T init) { /* 将[first, last)的值累加到init上 * 最后返回结果 */ for ( ; first != last; ++first) init = init + *first; return init; } //这里多提供了一个BinaryOperation参数。之前是执行的求和运算,现在换成binary_op,对每个元素执行binary_op操作,换成减法、乘法都可以,但是并不建议换成违背函数本意的操作。 template <class InputIterator, class T, class BinaryOperation> T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op) { for ( ; first != last; ++first) init = binary_op(init, *first); return init; }
inner_product
该函数用于计算[first1, last1)和[first2, first2 + (last1 - first1))的点积,最后加上init的值。template <class InputIterator1, class InputIterator2, class T> T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init) { //遍历[first1, last)以及[first2, first2 + (last1 - first1)) for ( ; first1 != last1; ++first1, ++first2) init = init + (*first1 * *first2); return init; } //该版本的inner_product不是执行init + (*fist1 ) * (*first2)操作,而是执行传入的binary_op1以及binary_op2操作 template <class InputIterator1, class InputIterator2, class T, class BinaryOperation1, class BinaryOperation2> T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2) { for ( ; first1 != last1; ++first1, ++first2) init = binary_op1(init, binary_op2(*first1, *first2)); return init; }
partial_sum
该函数用于计算局部的和。将*result赋值为
*first,将
*(result+1)赋值为
*first + *(first+1)依次类推。
当传入的迭代器
result为
first,这就变成了一个质变算法了。
//该函数供partial_sum调用 template <class InputIterator, class OutputIterator, class T> OutputIterator __partial_sum(InputIterator first, InputIterator last, OutputIterator result, T*) { //从first + 1指向的位置开始进行累加并赋值给*result T value = *first; while (++first != last) { value = value + *first; *++result = value; } //注意返回的是result + (last - first)的位置,即当前被赋值末尾元素的下一个位置 return ++result; } //partial_sum算法,版本一 template <class InputIterator, class OutputIterator> OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result) { //处理特殊情况,若first等于last,直接返回 if (first == last) return result; //将*result赋值为*first *result = *first; //从first + 1开始遍历累加,并将结果返回 return __partial_sum(first, last, result, value_type(first)); } //这是针对提供了BinaryOperation的partial_sum算法版本实现的 template <class InputIterator, class OutputIterator, class T, class BinaryOperation> OutputIterator __partial_sum(InputIterator first, InputIterator last, OutputIterator result, T*, BinaryOperation binary_op) { //不同之处在于之前的累加操作换成了binary_op二元操作 T value = *first; while (++first != last) { value = binary_op(value, *first); *++result = value; } return ++result; } //partial_sum版本二,提供了自己的二元操作 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
该函数用于计算[first, last)中相邻元素之间的差。它将
*result的值赋为
*first,然后在
[first+1, last)范围内的元素,分别计算
*(first) - *(first-1)的值,然后分别赋值给
*(result + 1)。
在不使用自己提供的
binary_op情况下,它和
partial_sum互为逆运算。比如
{1, 2, 3, 4, 5},执行
adjacent_difference之后,结果为
{1, 1, 1, 1, 1},然后再对
{1, 1, 1, 1, 1}执行
partial_sum,结果又恢复成了原样,为
{1, 2, 3, 4, 5}。
//该函数实现了adjacent_difference函数的主要功能,供adjacent_difference调用。和__partial_sum的实现很像,就是执行的二元操作不一样而已。 template <class InputIterator, class OutputIterator, class T> OutputIterator __adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, T*) { T value = *first; while (++first != last) { T tmp = *first; *++result = tmp - value; value = tmp; } return ++result; } //adjacent_difference,版本一 template <class InputIterator, class OutputIterator> OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result) { if (first == last) return result; *result = *first; return __adjacent_difference(first, last, result, value_type(first)); } //为提供了binary_op的adjacent_difference版本提供主要操作 template <class InputIterator, class OutputIterator, class T, class BinaryOperation> OutputIterator __adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, T*, BinaryOperation binary_op) { T value = *first; while (++first != last) { T tmp = *first; *++result = binary_op(tmp, value); value = tmp; } return ++result; } //adjacent_difference,版本二 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
该函数是SGI专属的算法,不在
STL的标准中。它的作用是计算x的n次方,当然也可以自己指定运算的类型,比如加法除法之类的。
// Returns x ** n, where n >= 0. Note that "multiplication" // is required to be associative, but not necessarily commutative. //指定运算类型 template <class T, class Integer, class MonoidOperation> T power(T x, Integer n, MonoidOperation op) { if (n == 0) return identity_element(op); else { //当n为偶数,不断的执行op,然后将n/2,直到n为奇数 while ((n & 1) == 0) { n >>= 1; x = op(x, x); } //对n为奇数时进行计算 T result = x; n >>= 1; while (n != 0) { x = op(x, x); if ((n & 1) != 0) result = op(result, x); n >>= 1; } return result; } } //调用上面的版本,通过multiplies<T>()表示做乘法运算 template <class T, class Integer> inline T power(T x, Integer n) { return power(x, n, multiplies<T>()); }
上面计算x的n次方的计算方式并不是依次相乘,而是采用的快速幂算法。区分奇偶,计算x^n的值,只需要O(logn)的复杂度,而不是O(n)。
快速幂算法的公式如下:
a^b = (a^2)^b/2,b为偶数
a^b = (a^2)^b/2*a,b为奇数
比如2的4次方,并没有采用
(2)*(2)*(2)*(2)这样依次相乘的算法,而是采用
(2*2)*(2*2),这样的做法,这种只用2次运算,而依次相乘需要4次运算。
itoa
该函数由SGISTL提供,并不在
STL标准中。
它并不是那个C语言里面实现的整数转字符串的函数。
而是在
[first, last)区间内将元素的值依次设置为
value, value + 1, value + 2......
这是一个质变算法,改变了传入的迭代器范围指向的元素的值。
template <class ForwardIterator, class T> void iota(ForwardIterator first, ForwardIterator last, T value) { while (first != last) *first++ = value++; }
小结
本小节对stl_numeric.h中的算法进行了分析,里面大部分算法都很简单,也就
power算法稍微需要理解下,如果有算法基础也很容易理解。除了注重算法本身,也要注意它是如何实现泛化的,这点同样也很重要。
相关文章推荐
- SGISTL源码探究-STL中的hashtable(上)
- SGISTL源码探究-stl_algo.h中的基础算法
- SGISTL源码探究-stl_alog.h中的二分查找算法
- SGISTL源码探究-stl_algo.h中的排列算法
- SGISTL源码探究-STL中的红黑树(下)
- SGISTL源码探究-STL中的算法(前言)
- SGISTL源码探究-STL中的红黑树(上)
- SGISTL源码探究-STL中的hashtable(下)
- SGISTL源码探究-stl_algo.h中的排序算法
- SGISTL源码探究-stl_algobase.h中的算法
- SGISTL源码探究-deque容器(上)
- SGISTL源码探究-stack配接器
- SGISTL源码探究-关联式容器:map
- SGISTL源码探究-traits技法
- SGISTL源码探究-queue配接器
- SGISTL源码探究-关联式容器:hash_map
- SGISTL源码探究-关联式容器:set
- SGISTL源码探究-第二级配置器
- SGISTL源码探究-vector容器(上)
- SGISTL源码探究-关联式容器:multiset