连接两个向量的最佳方法是什么?

时间:2010-07-05 04:36:54

标签: c++ vector

我正在使用多线程并希望合并结果。例如:

std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;

我希望AB按顺序拥有A的内容和B的内容。做这样的事情最有效的方法是什么?

8 个答案:

答案 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 + vector2vector4 += 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 |)。根据向量的大小和所需的串联操作数,这可能会成为瓶颈。上面的技巧可以解决这个问题。

一些需要考虑的东西

  • 仅当您真的知道在处理引用时在做什么,才应该这样做。 此解决方案旨在解决所提出问题的特定目的,并且效果很好。如果您不确定引用的工作方式,则在其他任何情况下使用它可能会导致意外行为。
  • 在此示例中,AB不仅提供了const,还提供了非常量 访问。随时将其删除。由于AB包含引用,因此要对其进行分配 值也会影响A和/或B中的原始元素。 理想的功能,这是应针对特定应用的问题 仔细考虑。
  • 同样,对A或B的任何更改(例如,分配值, 调整大小等)也将“修改” AB。这不一定不好 (实际上,它非常方便:AB不需要显式 已更新,以使其与A和B保持同步),但是 当然是一种必须意识到的行为。
  • 因为对元素的每次访问都必须先进行测试(即,“ i
  • 这种方法可以推广到n个向量。我没有尝试,但是 没什么大不了的。
  • (在我看来)将复制构造函数提供给 这样的代理(因为它们毕竟不是矢量)。
  • 无法(或至少太过简单)无法进行全局排序 VecProxy,因为并非所有元素都属于同一容器。

答案 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());