J'utilise le multitreading et je souhaite fusionner les résultats. Par exemple:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
Je veux qu'AB ait le contenu de A et le contenu de B dans cet ordre. Quelle est la manière la plus efficace de faire quelque chose comme ça?
Réponses:
AB.reserve( A.size() + B.size() ); // preallocate memory AB.insert( AB.end(), A.begin(), A.end() ); AB.insert( AB.end(), B.begin(), B.end() );
la source
C'est précisément à cela que
std::vector::insert
sert la fonction membrestd::vector<int> AB = A; AB.insert(AB.end(), B.begin(), B.end());
la source
insert
sur les itérateurs à accès aléatoire et était réservée à l'avance.distance
a une complexité O (1)). Néanmoins, les garanties de performance deinsert
sont quelque chose dont il faut tenir compte lorsque vous pouvez souvent faire mieux en planifiant à l'avance.size < capacity
plupart du temps, la prédiction de branchement entraînera probablement le fait que les instructions de la branche non réallouées se trouvent dans le pipeline d'instructions, minimisant la latence induite par la branche, sauf pour un faible nombre d'itérations. Cela suppose une bonne implémentation vectorielle, plus un pipeline d'instructions CPU et une [bonne] prédiction de branche, mais ce sont des hypothèses assez fiables pour une chaîne d'outils et une machine de bureau modernes. Je ne sais pas sur les smartphones cependant ..Cela dépend si vous avez vraiment besoin de concaténer physiquement les deux vecteurs ou que vous voulez donner l'apparence d'une concaténation pour le plaisir de l'itération. La fonction boost :: join
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
vous donnera ceci.
std::vector<int> v0; v0.push_back(1); v0.push_back(2); v0.push_back(3); std::vector<int> v1; v1.push_back(4); v1.push_back(5); v1.push_back(6); ... BOOST_FOREACH(const int & i, boost::join(v0, v1)){ cout << i << endl; }
devrait te donner
1 2 3 4 5 6
Remarque boost :: join ne copie pas les deux vecteurs dans un nouveau conteneur mais génère une paire d'itérateurs (plage) qui couvrent l'étendue des deux conteneurs. Il y aura une surcharge de performances, mais peut-être moins que de copier d'abord toutes les données dans un nouveau conteneur.
la source
Sur la base de la réponse de Kiril V. Lyadvinsky , j'ai fait une nouvelle version. Cet extrait utilise un modèle et une surcharge. Avec lui, vous pouvez écrire
vector3 = vector1 + vector2
etvector4 += vector3
. J'espère que cela peut vous aider.template <typename T> std::vector<T> operator+(const std::vector<T> &A, const std::vector<T> &B) { std::vector<T> AB; AB.reserve(A.size() + B.size()); // preallocate memory AB.insert(AB.end(), A.begin(), A.end()); // add A; AB.insert(AB.end(), B.begin(), B.end()); // add B; return AB; } template <typename T> std::vector<T> &operator+=(std::vector<T> &A, const std::vector<T> &B) { A.reserve(A.size() + B.size()); // preallocate memory without erase original data A.insert(A.end(), B.begin(), B.end()); // add B; return A; // here A could be named AB }
la source
::
est pris;)v1 + v2
ne représente pas l'addition.@
comme en F #Dans le sens de la réponse de Bradgonesurfing, souvent, on n'a pas vraiment besoin de concaténer deux vecteurs (O (n)), mais plutôt de travailler avec eux comme s'ils étaient concaténés (O (1)) . Si tel est votre cas, cela peut être fait sans avoir besoin des bibliothèques Boost.
L'astuce consiste à créer un proxy vectoriel: une classe wrapper qui manipule les références aux deux vecteurs, vu extérieurement comme un seul et contigu.
USAGE
std::vector<int> A{ 1, 2, 3, 4, 5}; std::vector<int> B{ 10, 20, 30 }; VecProxy<int> AB(A, B); // ----> O(1). No copies performed. for (size_t i = 0; i < AB.size(); ++i) std::cout << AB[i] << " "; // 1 2 3 4 5 10 20 30
LA MISE EN OEUVRE
template <class T> class VecProxy { private: std::vector<T>& v1, v2; public: VecProxy(std::vector<T>& ref1, std::vector<T>& ref2) : v1(ref1), v2(ref2) {} const T& operator[](const size_t& i) const; const size_t size() const; }; template <class T> const T& VecProxy<T>::operator[](const size_t& i) const{ return (i < v1.size()) ? v1[i] : v2[i - v1.size()]; }; template <class T> const size_t VecProxy<T>::size() const { return v1.size() + v2.size(); };
PRINCIPAL AVANTAGE
C'est O (1) (temps constant) pour le créer, et avec une allocation de mémoire supplémentaire minimale.
QUELQUES CHOSES À CONSIDÉRER
la source
Une variante plus simple qui n'a pas encore été mentionnée:
copy(A.begin(),A.end(),std::back_inserter(AB)); copy(B.begin(),B.end(),std::back_inserter(AB));
Et en utilisant l'algorithme de fusion:
#include <algorithm> #include <vector> #include <iterator> #include <iostream> #include <sstream> #include <string> template<template<typename, typename...> class Container, class T> std::string toString(const Container<T>& v) { std::stringstream ss; std::copy(v.begin(), v.end(), std::ostream_iterator<T>(ss, "")); return ss.str(); }; int main() { std::vector<int> A(10); std::vector<int> B(5); //zero filled std::vector<int> AB(15); std::for_each(A.begin(), A.end(), [](int& f)->void { f = rand() % 100; }); std::cout << "before merge: " << toString(A) << "\n"; std::cout << "before merge: " << toString(B) << "\n"; merge(B.begin(),B.end(), begin(A), end(A), AB.begin(), [](int&,int&)->bool {}); std::cout << "after merge: " << toString(AB) << "\n"; return 1; }
la source
Si vos vecteurs sont triés *, vérifiez set_union depuis <algorithm>.
Il y a un exemple plus complet dans le lien
* merci rlbond
la source
Toutes les solutions sont correctes, mais j'ai trouvé plus simple d'écrire simplement une fonction pour l'implémenter. comme ça:
template <class T1, class T2> void ContainerInsert(T1 t1, T2 t2) { t1->insert(t1->end(), t2->begin(), t2->end()); }
De cette façon, vous pouvez éviter le placement temporaire comme ceci:
la source