std::list::merge()是最直接的合并方式,要求两链表均已升序排列、类型一致且非const;它原地合并、时间复杂度o(n+m),rhs变为空;手动遍历适用于只读或需定制逻辑场景;避免使用std::merge()处理list。

std::list::merge() 是最直接的合并方式
如果两个 std::list 都已升序排列,且元素类型支持 operator(或你提供了自定义比较器),直接调用 <code>merge() 成员函数即可。它原地合并,时间复杂度 O(n+m),不分配新节点,也不改变原有 list 的所有权。
注意:调用方 list(即 lhs.merge(rhs) 中的 lhs)会吸收 rhs 的所有节点,rhs 变为空列表。这不是拷贝,是节点指针的重连 —— 所以要求两个 list 类型完全一致(包括 allocator)。
- 必须确保两个 list 都已有序,否则结果未定义
-
rhs在 merge 后处于有效但空的状态,不可再访问其元素 - 若需降序合并,传入
std::greater<t>{}</t>作为第二参数 - 不能对
constlist 调用merge()
手动遍历合并适用于只读场景或自定义逻辑
当不能修改原 list(比如参数是 const 引用),或需要在合并过程中做额外判断(如去重、过滤、转换),就得手写双指针遍历。这时用两个迭代器分别推进,逐个比较、插入到新 list 中。
关键点在于避免重复解引用和边界处理:一个 list 耗尽后,另一段剩余节点应整体 splice 或 insert,而不是继续循环单个 push_back —— 否则性能退化为 O(n×m)。
- 用
std::list::splice()接收剩余段,比循环push_back()更高效 - 比较时用
*it1 ,而非 <code>it1 (迭代器不可比) - 插入到新 list 时,
emplace_back()比push_back()略优(避免临时对象)
std::merge() 算法不适用于 std::list 的直接合并
std::merge() 要求输出迭代器支持随机访问或至少可递增赋值(如 std::back_inserter),但它对 std::list 输出效率极差:每次 back_inserter 插入都触发一次节点分配和链表尾部更新,O(1) 操作叠加成 O(n) 总开销。实测比 merge() 成员函数慢 3–5 倍。
- 除非你把 list 转成 vector 再 merge,否则别用
std::merge()处理 list - 若坚持用算法,改用
std::inplace_merge()前需先拼接再排序 —— 完全违背“有序输入”前提,得不偿失
常见错误:混用不同比较规则或忽略 const 正确性
最常踩的坑是:两个 list 一个用默认 operator 排序,另一个用 <code>std::greater,却直接调 merge() —— 结果乱序且难以调试。另一个是把 const list 传给需要非常量成员函数的接口,编译失败。
- 检查两个 list 的排序依据是否一致:打印前几项 +
std::is_sorted()验证 - 若函数参数是
const std::list<t>&</t>,就不能调merge();必须复制一份再操作 - 自定义类型务必重载
operator,或确保传入的比较器与排序时一致
std::list::merge() 的“原地接管”语义和 const 限制容易被忽略,实际写的时候多看一眼调用前后两个 list 的状态。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











