SGISTL源码探究-stl_numeric.h中的数值算法

来源:互联网 发布:java file.getlength 编辑:程序博客网 时间:2024/06/05 04:45

前言

上一小节中,我们对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)依次类推。
当传入的迭代器resultfirst,这就变成了一个质变算法了。

//该函数供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算法稍微需要理解下,如果有算法基础也很容易理解。除了注重算法本身,也要注意它是如何实现泛化的,这点同样也很重要。

原创粉丝点击