您的位置:首页 > 其它

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
算法稍微需要理解下,如果有算法基础也很容易理解。除了注重算法本身,也要注意它是如何实现泛化的,这点同样也很重要。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: