引言:为什么要拼接向量,以及为什么这很困难?
\n\n你好,同行!如果你曾经用C++编写过处理数据列表的代码,那么你肯定遇到过这样的问题:“我有两个std::vector,如何将它们合并成一个?”这个问题在Stack Overflow上非常热门(有数千次浏览!),这并非没有原因。乍一看似乎很简单:像Python那样用vector1 + vector2?但事实并非如此。在C++中,向量没有定义+运算符。我们得想办法。
今天,我们将详细讨论两个std::vector的拼接。我将向你展示3种经过验证的方法,解释何时使用哪种方法,并提醒你注意即使是经验丰富的开发人员也容易踩的坑。我们开始吧!
\n\n方法1:insert() —— 经典方法
\n\n最明显且最常用的方法是insert()方法。它允许将一个向量的所有元素插入到另一个向量的末尾。语法简单而优雅:
#include <iostream>\n#include <vector>\n\nint main() {\n std::vector<int> vec1 = {1, 2, 3};\n std::vector<int> vec2 = {4, 5, 6};\n\n // 拼接:将vec2插入到vec1的末尾\n vec1.insert(vec1.end(), vec2.begin(), vec2.end());\n\n // 输出:1 2 3 4 5 6\n for (int v : vec1) std::cout << v << " ";\n return 0;\n}\n\n工作原理:我们告诉编译器:“从vec1.end()位置开始(即第一个向量的最后一个元素之后),复制vec2.begin()和vec2.end()之间的所有内容”。瞧——C++向量合并完成了。
insert()的优缺点
\n- \n
- ✅ 优点:简单、可读性强、适用于任何类型。 \n
- ❌ 缺点:如果
vec1很小而vec2很大,插入时可能会发生多次内存重新分配。这会降低向量连接大量数据时的性能。 \n
建议:如果你知道最终大小,请提前调用vec1.reserve(vec1.size() + vec2.size())。这将避免不必要的内存分配。
方法2:std::merge() —— 用于已排序数据
\n\n如果你的向量已经排序了呢?或者你不仅需要拼接,还需要得到一个统一的排序数组?这时,来自头文件<algorithm>的std::merge算法就登场了。
#include <iostream>\n#include <vector>\n#include <algorithm> // 用于 std::merge\n\nint main() {\n std::vector<int> vec1 = {1, 3, 5};\n std::vector<int> vec2 = {2, 4, 6};\n std::vector<int> result;\n\n // 预留空间以避免不必要的复制\n result.reserve(vec1.size() + vec2.size());\n\n // 合并两个已排序的范围\n std::merge(vec1.begin(), vec1.end(),\n vec2.begin(), vec2.end(),\n std::back_inserter(result));\n\n // 输出:1 2 3 4 5 6\n for (int v : result) std::cout << v << " ";\n return 0;\n}\n\n请注意:std::merge要求两个输入范围都按升序排序。如果不是这样,结果将不可预测。但如果数据是有序的,这种方法在性能上堪称王者:时间复杂度为O(n + m)。
何时使用std::merge?
\n- \n
- 当你合并两个SQL查询的结果或按时间排序的日志时。 \n
- 当你需要的不仅仅是连接两个std::vector,而是排序后的合并时。 \n
- 当原始向量不能被修改时(我们创建第三个向量
result)。 \n
方法3:移动语义 —— C++11及更高版本的性能之选
\n\n假设你不再需要原始向量了