【问题标题】:How to add element by element of two STL vectors?如何逐个添加两个 STL 向量的元素?
【发布时间】:2010-07-30 23:45:43
【问题描述】:

这个问题很愚蠢,但我需要以一种非常有效的方式来做——它将在我的代码中一遍一遍地执行。我有一个返回向量的函数,我必须将返回的值逐个元素添加到另一个向量中。很简单:

vector<double> result;
vector<double> result_temp
for(int i=0; i< 10; i++) result_temp.push_back(i);

result += result_temp //I would like to do something like that.
for(int i =0; i< result_temp.size();i++)result[i] += result_temp[i]; //this give me segfault

我正在尝试做的数学运算是

u[i] = u[i] + v[i] 对于所有 i

可以做什么?

谢谢

编辑:添加了一个简单的初始化,因为这不是重点。结果应该如何初始化?

【问题讨论】:

  • 你会发布一些可编译的代码吗?如果没有看到这些向量是如何初始化的,“这给了我一个段错误”并不是特别有用。最可能的问题是其中一个向量比另一个长。如果不查看所有代码,真的很难判断你的代码哪里错了:-)
  • 我支持@James McNellis - 只要resultresult_temp 的长度相同,这段代码似乎是正确的。另外——你为什么声明result,但使用变量result_v——代码是这样写的吗?如果是这样,那就是个问题

标签: c++ stl vector


【解决方案1】:

看起来问题在于访问不存在的result 值。 tzaman 展示了如何将结果初始化为 10 个元素,每个元素的值为 0。

现在您需要调用transform 函数(来自),应用plus 函数对象(来自):

std::transform(result.begin(), result.end(), result_temp.begin(),
               result.begin(), std::plus<double>());

这将迭代 resultresult_temp,应用添加双精度的 plus,并将总和写回 result

【讨论】:

    【解决方案2】:

    如果您尝试将一个vector 附加到另一个,您可以使用类似以下的内容。这些来自我的一个实用程序库——std::vector 的两个 operator+= 重载:一个将单个元素附加到 vector,另一个附加整个 vector

    template <typename T>
    std::vector<T>& operator+=(std::vector<T>& a, const std::vector<T>& b)
    {
        a.insert(a.end(), b.begin(), b.end());
        return a;
    }
    
    template <typename T>
    std::vector<T>& operator+=(std::vector<T>& aVector, const T& aObject)
    {
        aVector.push_back(aObject);
        return aVector;
    }
    

    如果您尝试执行求和(即创建一个新的 vector,其中包含其他两个 vectors 的元素的总和),您可以使用类似以下的内容:

    #include <algorithm>
    #include <functional>
    
    template <typename T>
    std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b)
    {
        assert(a.size() == b.size());
    
        std::vector<T> result;
        result.reserve(a.size());
    
        std::transform(a.begin(), a.end(), b.begin(), 
                       std::back_inserter(result), std::plus<T>());
        return result;
    }
    

    您可以类似地实现operator+= 重载。

    【讨论】:

    • 谢谢,但我不是要在向量的末尾附加一个值,而是要尝试将向量元素的现有值与另一个向量的值相加。向量的大小始终是固定的。
    • @Ivan:查看编辑;在我看到您回复 Greg 的回答的评论之前,我并不完全确定您在寻找什么。
    • @James 忽略我原来的评论 - 现在你已经有了花哨和相关的代码 :)
    • 这看起来很棒而且很干净,但如果效率是主要问题,我认为这实际上会比简单地迭代元素并将它们添加在一起要慢。
    • 如果这比手动循环慢,我会感到惊讶。 (假设您在启用优化的情况下进行编译)
    【解决方案3】:

    Jon Reid 回答的具体例子:

    std::array<double,3> a = {1, 2, 3};
    std::array<double,3> b = {4, 5, 6};
    std::transform(a.begin( ), a.end( ), b.begin( ), a.begin( ),std::plus<double>( ));
    ASSERT_TRUE(a[0] == 5);
    ASSERT_TRUE(a[1] == 7);
    ASSERT_TRUE(a[2] == 9);
    

    【讨论】:

      【解决方案4】:

      您需要先将result 初始化为全零;只是声明变量实际上并没有分配任何元素。

      试试这个:

      vector<double> result(10); // default-initialize to 10 elements
      vector<double> result_temp;
      for(int i=0; i< 10; i++) 
          result_temp.push_back(i);
      
      for(int i =0; i< result_temp.size();i++)
          result[i] += result_temp[i];
      

      【讨论】:

        【解决方案5】:

        如果您的代码有段错误,那么这是正确性问题,而不是效率问题。

        为了实现“u[i] = u[i] + v[i] for all i”,我基本上会做你所做的:

        assert(u.size() == v.size()); // will fail with your initialization code, since
                                      // your "result" has size 0, not size 10.
                                      // perhaps do u.resize(v.size());
        for (size_t i = 0; i < u.size(); ++i) {
            u[i] += v[i];
        }
        

        如果您真的很在意程序的性能(也就是说,您编写了一个基本版本并且速度太慢,以至于您的程序无法满足某些要求,并且您已经证明这是大部分时间的代码被采取),那么你可以尝试:

        • 在编译器中启用大量优化(实际上,即使没有性能问题,我通常也会默认这样做),
        • 使用迭代器而不是索引(很少有太大区别,但很容易比较两者),
        • 稍微展开循环(可以产生有价值的速度差异,但这对特定情况非常敏感,并且会导致编码错误)。
        • 查看特定于平台的 SIMD 指令而不是 C++。然后对这些指令使用嵌入式汇编器或编译器内部函数。

        不过,在代码正确之前,您无需担心性能问题 ;-)。 “让它发挥作用,让它正确,让它快速”是一个合理的座右铭,尽管您通常不需要走到第 3 步。

        std::valarray 实际上拥有您想要的 operator+=。在用 valarrays 替换所有向量之前,请注意,这并不一定意味着它比简单的循环“更有效”——我不知道实现者对 valarray 的重视程度。您始终可以查看实现中的源代码。我也不知道为什么valarray 的多数据算术功能没有被定义为vector 的一部分,但通常是有原因的。

        【讨论】:

          【解决方案6】:

          代码看起来不错,但我的第一个倾向是更改使用值填充向量的任何代码,以添加到第一个向量中的值以获取对第一个向量的引用并直接添加到它而不是创建返回的新向量。那只是效率低下。

          如果你不能以这种方式改变函数,也许你可以改变它,让它引用一个它清除的向量,然后将值插入,这样你就不会复制向量。如果你做得很多,那可能会很昂贵。

          如果你想尽可能快地得到这个,另一个挑剔,你应该使用迭代器的前增量而不是后增量。在处理重载运算符而不是内置类型时,无法优化后增量创建的临时变量。因此,您在循环的每次迭代中都不断创建和销毁一个临时对象。 编辑: 正如 cmets 中所指出的,您在这里使用的是索引而不是迭代器(我显然没有给予足够的关注),所以这一点建议在这里并不适用。但是,在您正在使用迭代器的情况下,它仍然有效。

          除此之外,如果您尝试将两个向量的所有元素相加,您所拥有的解决方案可能与您将获得的一样有效。如果您关心的是将一个向量的元素插入另一个向量,则有更好的方法,但如果您只是将它们的值相加,那么您所拥有的看起来不错。由于额外的函数调用,我希望使用任何 STL 算法充其量都一样快并且可能更慢,但您可能必须对其进行分析才能确定。

          【讨论】:

          • “你应该在迭代器中使用前置增量而不是后置增量”。没错,但他没有使用迭代器,他使用的是整数索引。很难在前后增量之间做出性能案例;-)
          • 啊,不错。我没有引起足够的重视。我很少使用索引而不是迭代器,我对后增量的直觉反应是非常消极的。我坚信始终使用前增量,除非您需要后增量。这样,您就不必担心临时文件是否会被优化掉。但是,在这种情况下,编译器在优化它时应该没有问题,并且后增量与前增量一样有效。
          • 是的,即使不考虑可能的性能问题,我也更喜欢预增量,但出于有争议的原因,我认为它更清晰易读。 “增量 i”拼写为“++ i”。很少有人同意。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-09
          • 1970-01-01
          • 1970-01-01
          • 2017-01-26
          • 2011-09-09
          • 1970-01-01
          相关资源
          最近更新 更多