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

jma*_*erx 173 c++ vector

我正在使用多线程并想要合并结果.例如:

std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
Run Code Online (Sandbox Code Playgroud)

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

Kir*_*sky 292

AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
Run Code Online (Sandbox Code Playgroud)

  • 它应该复制每个元素,所以它是O(n) (6认同)
  • 谢谢!不会想到储备. (3认同)
  • 不确定是否要问一个新问题,但是在考虑移动语义时可以改进这个答案吗?有什么方法可以让我期望/指示编译器执行单个内存移动而不是循环遍历所有元素? (2认同)
  • @boycy否。将一个元素push_back摊销固定的时间。推回n个元素为O(n) (2认同)

Shi*_*rik 54

这正是成员函数std::vector::insert的用途

std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
Run Code Online (Sandbox Code Playgroud)

  • @Nick:如果每个现代stdlib实现都专门在随机访问迭代器上进行`insert`并保留在前面,我不会感到惊讶. (7认同)
  • @Nick:相比什么慢? (4认同)
  • 也许它会在元素的每个插入上检查足够的空间?预先使用预留将加快速度. (2认同)
  • @RvdK检查空间只有几个指令:负载容量,比较大小,条件跳转; 对于大多数情况,所有这些都是微不足道的.由于大多数时候"大小<容量",分支预测可能会导致非重新分配分支的指令位于指令流水线中,从而最小化分支引发的延迟,除了低迭代计数.这假设一个良好的向量实现,加上CPU指令管道和[好]分支预测,但这些是对现代工具链和台式机的非常可靠的假设.虽然不知道智能手机.. (2认同)

bra*_*ing 26

取决于您是否真的需要物理连接两个向量,或者您希望给出迭代的连接外观.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;
}
Run Code Online (Sandbox Code Playgroud)

应该给你

1
2
3
4
5
6
Run Code Online (Sandbox Code Playgroud)

注意boost :: join不会将两个向量复制到一个新容器中,而是生成一对覆盖两个容器跨度的迭代器(范围).将会有一些性能开销,但可能会少于将所有数据首先复制到新容器.


Ron*_*sse 10

在 Bradgonesurfing 的回答的方向上,很多时候人们并不真的需要连接两个向量 (O(n)),而只是像连接它们一样处理它们 (O(1))。如果这是你的情况,它可以在不需要 Boost 库的情况下完成。

诀窍是创建一个向量代理:一个包装类,它操作对两个向量的引用,外部视为一个连续的向量。

用法

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
Run Code Online (Sandbox Code Playgroud)

执行

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(); };
Run Code Online (Sandbox Code Playgroud)

主要优势

创建它是 O(1)(恒定时间),并且需要最少的额外内存分配。

一些需要考虑的事情

  • 只有当你真正知道处理引用时你在做什么时,你才应该去做此解决方案旨在针对所提出问题的特定目的,对此效果很好。如果您不确定引用的工作方式,在任何其他上下文中使用它可能会导致意外行为。
  • 在这个例子中,AB并没有提供一种非const访问运算符([])。随意包含它,但请记住:由于 AB 包含引用,因此为其分配值也会影响 A 和/或 B 中的原始元素。这是否是一个理想的功能,这是一个特定于应用程序的问题,应该仔细考虑。
  • 直接对 A 或 B 进行的任何更改(如赋值、排序等)也将“修改”AB。这不一定是坏事(实际上,它可能非常方便:AB 永远不需要显式更新以保持自身与 A 和 B 同步),但它肯定是一种必须注意的行为。重要的例外:将 A 和/或 B 调整为更大可能会导致它们在内存中重新分配(为了需要连续空间),这反过来会使 AB 无效。
  • 因为每次访问一个元素之前都要进行一次测试(即“i < v1.size()”),VecProxy 访问时间虽然恒定,但也比向量慢一点。
  • 这种方法可以推广到 n 个向量。我没试过,但应该没什么大不了的。

  • 正是我需要的,非常感谢 (2认同)

alo*_*ica 8

根据Kiril V. Lyadvinsky的回答,我做了一个新版本.此代码段使用模板和重载.有了它,你可以写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
}
Run Code Online (Sandbox Code Playgroud)

  • @SR 我的意思是连接。我在 3 年前写了这个答案。我仍然知道它是什么意思。没有问题。如果 C++ 可以提​​供自己的重载,那就更好了。(是的`::`被采用;) (2认同)