std::list::reverse() 是反转 std::list 的首选方法,时间复杂度 O(n),仅交换节点指针、不重分配内存、不触发元素构造/析构,且迭代器不失效;误用 std::reverse 会因迭代器类型不匹配而编译失败。

std::list::reverse() 是最直接的反转方式
对 std::list 反转,首选就是它自带的 reverse() 成员函数。这不是算法,而是容器原生支持的操作,时间复杂度 O(n),但不涉及内存重分配,只交换节点指针,非常高效。
常见错误是误用 std::reverse 算法——它要求随机访问迭代器,而 std::list::iterator 是双向迭代器,编译会直接报错:error: no match for 'operator+'。
- 正确写法:
my_list.reverse(); - 错误写法:
std::reverse(my_list.begin(), my_list.end());(编译失败) - 注意:
reverse()是就地操作,无返回值,原容器被修改
需要保留原 list 时,得手动拷贝再反转
如果不能修改原始 std::list,比如要同时持有正序和倒序版本,就得先构造副本:
std::list<int> original = {1, 2, 3, 4};
std::list<int> reversed = original; // 拷贝构造
reversed.reverse();
这里没有“深拷贝陷阱”,因为 std::list 的拷贝是浅拷贝(节点数据按值复制),只要元素类型可拷贝就没问题。
立即学习“C++免费学习笔记(深入)”;
- 若元素是裸指针(如
int*),拷贝后两个 list 指向同一块内存,后续delete容易 double-free - 推荐改用智能指针(
std::unique_ptr<T>或std::shared_ptr<T>)避免资源管理问题 - 拷贝本身是 O(n) 时间 + O(n) 空间,和
reverse()一样开销,但多一次遍历
反转后迭代器仍有效,但顺序已变
std::list::reverse() 不会使已有迭代器失效——这是 std::list 的关键优势之一。但要注意语义变化:
- 原先指向首元素的
begin()迭代器,反转后指向原尾元素(即新尾) - 原先
--end()得到的尾元素,反转后变成首元素,但该迭代器本身没变,只是所指位置逻辑变了 - 如果你缓存了某个迭代器(比如
auto it = my_list.begin();),反转后*it仍是原来那个值,但它现在处于新序列的末尾位置
所以反转后继续用旧迭代器遍历,行为符合新顺序,但别假设它还对应“第一个”或“最后一个”逻辑位置。
性能对比:list::reverse vs 手动插入构建反向 list
有人想通过遍历原 list、用 push_front() 构建新 list 来实现反转,这也能得到正确结果,但没必要:
-
list::reverse():单次遍历,仅修改指针,常数级额外空间 -
push_front()构建:单次遍历 + n 次节点分配(即使内存池优化,也比指针交换重) - 实测在千级以上元素时,
reverse()快 2–3 倍,且更省内存 - 除非你要在反转同时做转换(比如
int→std::string),否则纯反转请直接调用成员函数
真正容易被忽略的是:反转操作本身不触发任何元素的构造/析构,哪怕元素类型有非平凡的移动构造函数,reverse() 也只挪指针——这点和 std::vector::reverse 的“交换元素值”有本质区别。


















