effective stl 第37条:使用accumulate或者for_each进行区间统计

注意算法accumulate并不位于algorithm这个库文件中,它和其他三个“数值算法”存在于中,另外的三个算法依次是inner_product/adjacent_difference/partial_sum。

#include<iostream>
#include<algorithm>
#include<numeric>
#include<list>
#include<iterator>
#include<vector>

using namespace std;

int stringLenSum(int stringNowSum, const string& s)
{
    return stringNowSum + s.size();
}

struct Point{
    Point(double initx, double inity) :x(initx), y(inity){};
    double x;
    double y;
};
class PointAverage :
    public binary_function<Point, Point, Point>{
public:
    PointAverage() :xSUm(0), ySUm(0), numPoints(0){};
    const Point operator()(const Point& avgSoFar, const Point& p)
    {
        ++numPoints;
        xSUm += p.x;
        ySUm += p.y;
        return Point(xSUm / numPoints, ySUm / numPoints);
    }
private:
    int numPoints;
    double xSUm;
    double ySUm;
};

class PointAverageForEach :
    public binary_function<Point, Point, Point>{
public:
    PointAverageForEach() :xSUm(0), ySUm(0), numPoints(0){};
    const Point operator()(const Point& avgSoFar, const Point& p)
    {
        ++numPoints;
        xSUm += p.x;
        ySUm += p.y;
    }
    Point result() const
    {
        return Point(xSUm / numPoints, ySUm / numPoints);
    }
private:
    int numPoints;
    double xSUm;
    double ySUm;
};

int main()
{
    list<double> ld;
    for (int i = 1; i <= 10; i++)
    {
        ld.push_back(i+0.4987);
    }

    double sumDouble = accumulate(ld.begin(), ld.end(), 0.0);
    double sumInt = accumulate(ld.begin(), ld.end(), 0);
    cout << sumDouble << endl;//输出为59.987,输出为double
    cout << sumInt << endl;//输出为59,因为初始化为0,所以是把每次的加法都转化为整数之后的总和

    //下边这段代码不太明白在干什么
    cout << "The sum of the ints on the standard input is:"
        << accumulate(istream_iterator<int>(cin), istream_iterator<int>(), 0)
        << endl;

    //下边这段代码演示用accumulate来计算字符串的总长度
    list<string> ss;
    //对ss的插入操作
    int sumLen = accumulate(ss.begin(), ss.end(), static_cast<int>(0), stringLenSum);

    vector<float> vf;
    float sumFloat = accumulate(vf.begin(), vf.end(), 1.0f, multiplies<float>());

    //下边是计算一个区间中所有点的平均值,这是使用的accumulate的方法
    list<Point> lp;
    Point avg = accumulate(lp.begin(), lp.end(), Point(0, 0), PointAverage());

    //下边是使用for_each的用法
    Point avg = for_each(lp.begin(), lp.end(), PointAverageForEach().result());

    return 0;
}

这工作得很好,而且仅因为我有时候和一些非常狂热的人打交道(他们中的很多都在标准委员会),所以我
才会预见到它可能失败的STL实现。不过,PointAverage和标准的第26.4.1节第2段冲突,我知道你想起来了,
那就是禁止传给accumulate的函数中有副作用。成员变量numPoints、xSum和ySum的修改造成了一个副作用,
所以,技术上讲,我刚展示的代码会导致结果未定义。实际上,很难想象它无法工作,但当我这么写时我被
险恶的语言律师包围着,所以我别无选择,只能在这个问题上写出难懂的条文。
那很好,因为它给我了一个机会来提起for_each,另一个可以用于统计区间而且没有accumulate那么多限制的
算法。正如accumulate,for_each带有一个区间和一个函数(一般是一个函数对象)来调用区间中的每个元
素,但传给for_each的函数只接收一个实参(当前的区间元素),而且当完成时for_each返回它的函数。(实
际上,它返回它的函数的一个拷贝——参见条款38。)值得注意的是,传给(而且后来要返回)for_each的函
数可能有副作用。
除了副作用问题,for_each和accumulate的不同主要在两个方面。首先,accumulate的名字表示它是一个产生区
间统计的算法,for_each听起来好像你只是要对区间的每个元素进行一些操作,而且,当然,那是那个算法
的主要应用。用for_each来统计一个区间是合法的,但是它没有accumulate清楚。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值