Как добавить поэлементно двух векторов STL?

26
задан Ivan 30 July 2010 в 23:54
поделиться

6 ответов

Если вы пытаетесь добавить один вектор к другому, вы можете использовать что-то вроде следующего. Это из одной из моих библиотек утилит - две перегрузки operator + = для std :: 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;
}

Если вы пытаетесь выполнить суммирование (то есть создать новый вектор , содержащий суммы элементов двух других вектора ] s) можно использовать что-то вроде следующего:

#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 + = .

31
ответ дан 28 November 2019 в 06:21
поделиться

Если в вашем коде есть ошибки, то это проблема правильности, а не эффективности.

Чтобы достичь «u [i] = u [i] + v [i] для всех 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+=, которое вы хотите. Прежде чем заменять все свои векторы на значения, имейте в виду, что это не обязательно означает, что он «более эффективен», чем простой цикл - я не знаю, насколько серьезно разработчики воспринимают это valarray. Вы всегда можете посмотреть на источник в вашей реализации. Я также не знаю, почему арифметическая функция нескольких данных в valarray не была определена как часть vector, но обычно есть причина.

1
ответ дан Steve Jessop 28 November 2019 в 06:21
поделиться

Код кажется нормальным, но мое первое желание было бы изменить любой код, заполняющий вектор значениями, чтобы добавить к значениям в первом векторе ссылку на первый вектор и добавить к ней непосредственно, а не создавать новый вектор, который возвращается. Это просто неэффективно.

Если вы не можете изменить функцию таким образом, возможно, вы можете изменить ее так, чтобы она брала ссылку на вектор, который она очищает, а затем вставляет значения, чтобы вы не копировали векторы вокруг. Это может дорого обойтись, если вы много делаете.

Еще один придирчивый, если вы пытаетесь получить это как можно быстрее, вы должны использовать преинкремент с итераторами, а не постинкремент. Временное, которое создает постинкремент, не может быть оптимизировано при работе с перегруженными операторами, а не со встроенными типами. Таким образом, вы продолжаете создавать и уничтожать временную каждую итерацию вашего цикла. РЕДАКТИРОВАТЬ: Как было отмечено в комментариях, вы используете индексы здесь, а не итераторы (я, очевидно, не уделял достаточного внимания), так что этот совет не применим здесь. Тем не менее, в тех случаях, когда вы используете итераторы, это все еще действует.

Кроме этого, если вы пытаетесь добавить все элементы двух векторов вместе, то, вероятно, у вас есть примерно такое же эффективное решение, которое вы получите. Есть лучшие способы, если вы беспокоитесь о вставке элементов одного вектора в другой, но если вы просто складываете их значения вместе, то у вас хорошо получается. Я ожидаю, что использование любых алгоритмов STL будет в лучшем случае столь же быстрым и, вероятно, медленным из-за дополнительных вызовов функций, но вам, вероятно, придется профилировать его, чтобы быть уверенным.

0
ответ дан Jonathan M Davis 28 November 2019 в 06:21
поделиться

Вам нужно сначала инициализировать 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];
1
ответ дан 28 November 2019 в 06:21
поделиться

Я с @James McNellis - этот код кажется правильным, если result и result_temp имеют одинаковую длину.

Также - почему вы объявили результат , но использовали переменную result_v - так ли на самом деле написан код? Если да, то это проблема

0
ответ дан 28 November 2019 в 06:21
поделиться

Похоже, что проблема заключается в обращении к несуществующим значениям result. tzaman показывает, как инициализировать result 10 элементами, каждый из которых имеет значение 0.

Теперь нужно вызвать функцию transform (из ), применяя объект функции plus (из ):

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

Это итерирует result и result_temp, применяет plus, который складывает удвоенные значения, и записывает сумму обратно в result.

35
ответ дан 28 November 2019 в 06:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: