std::merge是最直接靠谱的做法,专为合并两个有序序列设计,需确保目标容器空间充足、输入迭代器合法,避免误用inplace_merge或手写双指针。

用 std::merge 是最直接靠谱的做法
别手写双指针循环,C++ 标准库早给你备好了——std::merge 就是专为这事设计的。它要求两个输入范围已排序,输出到一个目标容器(可以是新 vector,也可以是已有空间),时间复杂度 O(m+n),且稳定、无额外分配(只要你提前 reserve 好)。
常见错误是直接传两个 vector 进去就完事,结果输出容器为空或容量不足,导致越界或性能暴跌。
- 必须确保目标容器有足够空间:用
reserve()预分配,或用back_inserter(但会触发多次 push_back,稍慢) - 输入迭代器必须合法:不能传空 vector 的
end()当 begin,尤其注意边界判断 - 如果原 vector 很大,别用
insert(v.end(), ...)拼接——那不是合并,是拼接,不保序也不高效
vector<int> a = {1, 3, 5}, b = {2, 4, 6, 7};
vector<int> merged;
merged.reserve(a.size() + b.size()); // 关键!
merge(a.begin(), a.end(), b.begin(), b.end(), back_inserter(merged));
原地合并?别碰 std::inplace_merge 除非你真需要
std::inplace_merge 看起来省空间,但它要求数据在**同一个容器里**、且被一个分界点分成两段有序区间。你手上是两个独立 vector,硬凑会先得把 b 插入 a 尾部,再调用它——这步 insert 就是 O(n) 移动,整体反而更慢,还可能触发多次内存重分配。
适用场景极窄:比如你维护一个大 vector,刚往末尾 push 了一批有序数据,想把它和前面部分合并,这时才值得考虑。
立即学习“C++免费学习笔记(深入)”;
- 对两个分离 vector,
inplace_merge不是优化,是自找麻烦 - 它内部可能用缓存,也可能不用,行为依赖 lib 实现,不可控
- 若真要“原地”,不如把 a 和 b swap 给一个临时 vector,再 merge 到 a,避免拷贝
自己写双指针?只在特殊约束下才值得
标准库 merge 已高度优化,手写通常没优势。但如果你明确知道数据特征(比如大量重复值、或需要定制比较逻辑、或要合并过程中过滤/转换),那才动手。
最容易踩的坑是边界处理:某一边走完后忘了把另一边全拷过去;或者用 而非 <code> 导致稳定性被破坏(<code>std::merge 是稳定归并)。
- 始终用
比较,保持稳定性(相同值时,左边元素优先) - 别用
size()循环计数,用迭代器走到end() - 如果 vector 元素是自定义类型,确保
operator 或传入的比较函数满足严格弱序
// 稳定的手写片段(仅作参考)
auto i = a.begin(), j = b.begin();
while (i != a.end() && j != b.end()) {
if (*i < *j) { merged.push_back(*i++); }
else { merged.push_back(*j++); }
}
merged.insert(merged.end(), i, a.end());
merged.insert(merged.end(), j, b.end());
性能关键:别让 vector 自动扩容拖垮 merge
无论用 std::merge 还是手写,最常被忽略的性能杀手就是没 reserve()。每次 push_back 触发扩容,可能复制已有数据,均摊下来接近 O((m+n)²)。
另一个隐形成本是 move vs copy:如果 vector 存的是大对象(如 string、自定义结构体),确保它们支持移动语义,否则 merge 过程全是深拷贝。
- 合并前一定调
merged.reserve(a.size() + b.size()) - 如果元素类型没有移动构造函数,考虑用
std::move_iterator包装输入迭代器(需 C++11+) - 调试时可加断点看
capacity()和size()差值,确认没意外扩容
std::merge)、预分配空间(reserve)、避开原地陷阱(别硬套 inplace_merge)。剩下都是围绕这三点的细节校验。










