如何总结C++向量的元素?

Pra*_*rav 218 c++ stl vector

找到a中所有元素之和的方法是std::vector什么?

假设我有一个std::vector<int> vector包含少量元素的向量.现在我想找到所有元素的总和.有什么不同的方式?

Pra*_*rav 400

实际上有很多方法.

int sum_of_elems = 0;
Run Code Online (Sandbox Code Playgroud)

C++ 03

  1. 循环经典:

    for(std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it)
        sum_of_elems += *it;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用标准算法:

    #include <numeric>
    
    sum_of_elems = std::accumulate(vector.begin(), vector.end(), 0);
    
    Run Code Online (Sandbox Code Playgroud)

    积累小心.最后一个参数的类型不仅用于初始值,还用于结果的类型.如果你在那里放一个int,即使向量有浮点数,它也会累积整数.如果要汇总浮点数,请更改00.00.0f(感谢nneonneo).

C++ 11及更高版本

  1. 使用std::for_each:

    std::for_each(vector.begin(), vector.end(), [&] (int n) {
        sum_of_elems += n;
    });
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用基于范围的for循环(感谢Roger Pate):

    for (auto& n : vector)
        sum_of_elems += n;
    
    Run Code Online (Sandbox Code Playgroud)

  • **注意`累积'.最后一个参数的类型不仅用于初始值,还用于结果的类型.如果你把`int`放在那里,即使向量有`float`,它也会累积`int`.结果可能是巧妙的错误,编译器会在不告诉您的情况下将结果强制转换为浮点数. (51认同)
  • 为什么你的lambda例子使用`for_each`?`accumulate`会更简洁(即使它不需要lambda) (8认同)
  • 当然在C++ 03中你可以使用带有仿函数的`std :: for_each`,它只需要比C++ 0x lambda定义更多行代码. (5认同)
  • @jalf:你的观点是正确的,我应该在`for_each`中使用`accumulate`,但这个例子不是很有用(用于学习目的),因为它表明我们也可以嵌套lambdas :-) (4认同)
  • 如果你有'累积',你为什么要使用`for_each`? (2认同)

pax*_*blo 34

Prasoon已经提供了许多不同的(和好的)方法来做到这一点,这里不需要重复.不过,我想建议一种替代的速度方法.

如果你要做这么多,你可能会考虑对你的向量进行"子类化",以便单独维护一个元素的总和(实际上不是由于缺少一个元素而导致的子类向量虚拟析构函数 - 我说的更多的是一个包含sum和一个向量的类,has-a而不是is-a,并提供类似矢量的方法).

对于空向量,总和设置为零.在向量的每次插入时,将要插入的元素添加到总和中.在每次删除时,减去它.基本上,任何可以改变基础向量的东西都会被拦截,以确保总和保持一致.

这样,你有一个非常有效的O(1)方法,用于在任何时间点"计算"总和(只返回当前计算的总和).在调整总数时,插入和删除时间会稍长,您应该考虑此性能影响.

需要比向量更多的总和更多的向量是可能受益于该方案的向量,因为计算总和的成本在所有访问中摊销.显然,如果你每小时只需要总和而且矢量每秒变化三千次,那就不合适了.

这样的东西就足够了:

class UberVector:
    private Vector<int> vec
    private int sum

    public UberVector():
        vec = new Vector<int>()
        sum = 0

    public getSum():
        return sum

    public add (int val):
        rc = vec.add (val)
        if rc == OK:
            sum = sum + val
        return rc

    public delindex (int idx):
        val = 0
        if idx >= 0 and idx < vec.size:
            val = vec[idx]
        rc =  vec.delindex (idx)
        if rc == OK:
            sum = sum - val
        return rc
Run Code Online (Sandbox Code Playgroud)

显然,这是伪代码,您可能希望获得更多功能,但它显示了基本概念.

  • 对不起,我应该更清楚 - 你可以使用与vector相同的方法创建自己的类,在其中维护一个`has-a`向量,而不是一个合适的子类(`is-a`). (7认同)
  • 有趣,但要小心,因为`std :: vector`不适用于子类化. (6认同)
  • 这种方法会导致基本向量运算的性能下降。 (2认同)

bea*_*ker 29

最简单的方法是使用std:accumuatevector<int> A:

#include <numeric>
cout << accumulate(A.begin(), A.end(), 0);
Run Code Online (Sandbox Code Playgroud)


Jam*_*lis 23

为什么可以向后执行向前求和?鉴于:

std::vector<int> v;     // vector to be summed
int sum_of_elements(0); // result of the summation
Run Code Online (Sandbox Code Playgroud)

我们可以使用下标,向后计数:

for (int i(v.size()); i > 0; --i)
    sum_of_elements += v[i-1];
Run Code Online (Sandbox Code Playgroud)

我们可以使用范围检查"下标",向后计数(以防万一):

for (int i(v.size()); i > 0; --i)
    sum_of_elements += v.at(i-1);
Run Code Online (Sandbox Code Playgroud)

我们可以在for循环中使用反向迭代器:

for(std::vector<int>::const_reverse_iterator i(v.rbegin()); i != v.rend(); ++i)
    sum_of_elements += *i;
Run Code Online (Sandbox Code Playgroud)

我们可以使用前向迭代器,在for循环中向后迭代(噢,棘手!):

for(std::vector<int>::const_iterator i(v.end()); i != v.begin(); --i)
    sum_of_elements += *(i - 1);
Run Code Online (Sandbox Code Playgroud)

我们可以使用accumulate反向迭代器:

sum_of_elems = std::accumulate(v.rbegin(), v.rend(), 0);
Run Code Online (Sandbox Code Playgroud)

我们可以使用for_each反向迭代器使用lambda表达式:

std::for_each(v.rbegin(), v.rend(), [&](int n) { sum_of_elements += n; });
Run Code Online (Sandbox Code Playgroud)

因此,正如您所看到的,有向后向量求和向量的方法与向前求和的总和相同,其中一些方法更令人兴奋,并为逐个错误提供了更大的机会.

  • 为什么不通过向模数运算符添加素数来循环遍历向量?:-) (35认同)
  • @paxdiablo你真的需要相对于`v.size()`的素数. (3认同)
  • @Lynn:如果向量的结尾在缓存中是热的(从之前的循环开始),那么是的,在当前的Intel x86 CPU上,向后循环可以明显更快.此外,将循环计数器计数到零可以将编译器中的指令保存到asm中,如果它不展开循环,这可能很重要.但是,当向前循环时,预取有时会稍微好一些,因此通常情况下总是向后循环并不是更好. (3认同)
  • 为什么会有这个答案?向后求和有什么好处,还是你只是在恶作剧? (2认同)

raf*_*fak 15

#include<boost/range/numeric.hpp>
int sum = boost::accumulate(vector, 0);
Run Code Online (Sandbox Code Playgroud)

  • `boost :: accumulate`只是`std :: accumulate`的包装. (7认同)
  • 非增强方式并不难:#include &lt;numeric&gt;和std :: accumulate(v.begin(),v.end(),(int64_t)0);`。请注意,初始累加器值的类型用作累加器类型,因此,如果要将8位元素求和到64位结果中,就可以这样做。 (2认同)

kri*_*iss 5

我是Perl用户,我们的一个游戏就是找到增加变量的每种不同方式......这在这里并没有什么不同.在C++中找到向量元素总和的方法的答案可能是an infinity......

我的2美分:

使用BOOST_FOREACH,摆脱丑陋的迭代器语法:

sum = 0;
BOOST_FOREACH(int & x, myvector){
  sum += x;
}
Run Code Online (Sandbox Code Playgroud)

迭代索引(真的很容易阅读).

int i, sum = 0;
for (i=0; i<myvector.size(); i++){
  sum += myvector[i];
}
Run Code Online (Sandbox Code Playgroud)

另一个是破坏性的,像堆栈一样访问矢量:

while (!myvector.empty()){
   sum+=myvector.back();
   myvector.pop_back();
}
Run Code Online (Sandbox Code Playgroud)


小智 5

仅限C++ 0x:

vector<int> v; // and fill with data
int sum {}; // or = 0 ... :)
for (int n : v) sum += n;
Run Code Online (Sandbox Code Playgroud)

这类似于其他地方提到的BOOST_FOREACH,与使用accumulate或for_each的有状态仿函数相比,在更复杂的情况下具有相同的清晰度.

  • 如果将for(int n:v)sum + = n;更改为for for(auto n:v)sum + = n ;,它将适用于任何矢量模板。我知道OP指的是vector &lt;int&gt;,但是这种方式稍微更通用:-) (3认同)

小智 5

一个人也可以std::valarray<T>这样使用

#include<iostream>
#include<vector>
#include<valarray>

int main()
{
    std::vector<int> seq{ 1,2,3,4,5,6,7,8,9,10 };
    std::valarray<int> seq_add{ seq.data(), seq.size() };
    std::cout << "sum = " << seq_add.sum() << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有些人可能发现这种方法没有效率,因为valarray需求的大小必须与向量的大小一样大,初始化valarray也将花费一些时间。

在这种情况下,请勿使用它,并将其作为总结序列的另一种方法。