前言
上一小节中,我们对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算法稍微需要理解下,如果有算法基础也很容易理解。除了注重算法本身,也要注意它是如何实现泛化的,这点同样也很重要。

本文深入探究STL中的stl_numeric.h文件,详细阐述了accumulate、inner_product、partial_sum、adjacent_difference和power等数值算法的原理与实现。文章通过源码分析,揭示了这些算法的泛型设计,并特别讨论了power函数的快速幂算法,以O(logn)的复杂度计算x的n次方。
1182

被折叠的 条评论
为什么被折叠?



