我正在使用多线程并希望合并结果。例如:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
我希望AB按顺序拥有A的内容和B的内容。做这样的事情最有效的方法是什么?
答案 0 :(得分:275)
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
答案 1 :(得分:48)
这正是成员函数std::vector::insert
的用途
std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
答案 2 :(得分:21)
取决于您是否真的需要物理连接两个向量,或者您希望给出迭代的连接外观。 boost :: join函数
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
会给你这个。
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;
}
应该给你
1
2
3
4
5
6
注意boost :: join不会将两个向量复制到一个新容器中 但会生成一对覆盖范围的迭代器(范围) 两个容器。可能会有一些性能开销 少于首先将所有数据复制到新容器。
答案 3 :(得分:8)
基于Kiril V. Lyadvinsky answer,我制作了一个新版本。此代码段使用模板和重载。有了它,您可以写vector3 = vector1 + vector2
和vector4 += vector3
。希望它可以提供帮助。
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
}
答案 4 :(得分:3)
一个更简单的变体,没有提到过:
copy(A.begin(),A.end(),std::back_inserter(AB));
copy(B.begin(),B.end(),std::back_inserter(AB));
并使用合并算法:
#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;
}
答案 5 :(得分:1)
按照Bradgonesurfing的回答,很多时候并不需要 串联两个向量,而只是像它们被串联一样与它们一起工作。这似乎是您的情况,并且无需使用Boost库就可以完成。
诀窍是创建一个向量代理:一个包装器类,该类处理对两个向量的引用,在外部被视为一个连续的向量,然后可以像您所做的那样对其进行访问/遍历在真实的向量上。
用法
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1)
for (size_t i = 0; i < AB.size(); i++)
std::cout << AB[i] << " "; // ----> Output: 1 2 3 4 5 10 20 30
std::cout << AB[6]; // ----> Output: 20
实施
template <class T>
class VecProxy {
private:
std::vector<T>& v1;
std::vector<T>& v2;
public:
VecProxy(std::vector<T>& ref1, std::vector<T>& ref2) : v1(ref1), v2(ref2) {}
T& operator[](const size_t& i);
const T& operator[](const size_t& i) const;
const size_t size() const;
};
template<class T>
T& VecProxy<T>::operator[](const size_t& i){
return (i < v1.size()) ? v1[i] : v2[i - v1.size()];
};
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(); };
主要优点
创建它的时间为O(1)(恒定时间),并且具有最少的额外内存分配。实际上,由于考虑了| B |的替换,因此即使在考虑巨大的向量时也是快速的操作。 (或| A | + | B |)元素复制为零。此外,它还提供了所需的行为。
向量级联至少为O(| B |)(当B附加到A时),与采用的技术无关。在您的情况下,由于您打算使用第三个向量AB,因此它是O(| A | + | B |)。根据向量的大小和所需的串联操作数,这可能会成为瓶颈。上面的技巧可以解决这个问题。
一些需要考虑的东西
答案 6 :(得分:0)
如果您的矢量已排序*,请查看&lt; algorithm&gt;中的set_union。
set_union(A.begin(), A.end(), B.begin(), B.end(), AB.begin());
链接中有一个更全面的例子
*感谢rlbond
答案 7 :(得分:0)
所有解决方案都是正确的,但我发现编写一个函数来实现它更容易。像这样:
template <class T1, class T2>
void ContainerInsert(T1 t1, T2 t2)
{
t1->insert(t1->end(), t2->begin(), t2->end());
}
这样你可以避免像这样的临时放置:
ContainerInsert(vec, GetSomeVector());