如何用C++实现栈结构stack

作者:袖梨 2026-07-27
std::stack默认底层容器是std::deque而非std::vector;可显式指定vector以获得连续内存;需注意拷贝/移动语义、析构调用、无迭代器、优先用empty()判空及异常安全。

std::stack 最快实现,但得知道它默认用什么容器

std::stack 不是独立容器,而是适配器——它底层默认用 std::deque,不是 std::vector。这点容易被忽略,导致性能误判。比如频繁扩容时,deque 的分段内存比 vector 更少触发整体拷贝,但随机访问慢;如果明确要连续内存和可控增长策略,可以显式指定:

std::stack<int, std::vector<int>> s;
这样构造后,s 就基于 vectorpush() 可能触发重分配,但 top()pop() 仍是 O(1)。

手写栈要注意拷贝/移动语义,尤其含资源的对象

自己实现栈类时,若模板参数类型是 std::string 或自定义类,必须正确处理构造、析构和赋值。常见错误是浅拷贝内部数组指针,或忘记在 pop() 后调用元素析构函数。C++11 起推荐用 std::unique_ptr<T[]> 管理内存,并在 push() 时用 new (ptr + size) T(std::move(value)) 定位构造,在 pop() 时显式调用 ptr[size-1].~T()。不这么做,std::string 类型的栈可能泄漏内存或重复析构。

std::stack 没有迭代器,遍历栈必须靠临时容器中转

标准库故意不提供 begin()/end(),因为这违背栈的 LIFO 抽象。真要打印全部内容或调试检查,不能直接 for-each。可行做法是:把栈元素逐个 pop()std::vector,再反向遍历(或用另一个栈暂存):

std::vector<int> tmp;<br>while (!s.empty()) {<br>  tmp.push_back(s.top());<br>  s.pop();<br>}<br>// 此时 tmp 是逆序,可正向遍历
注意:这个操作会清空原栈。如需保留,得先拷贝一份——而 std::stack 不支持拷贝构造(除非底层容器支持),所以更稳妥的是从头重建。

std::stack 时别依赖 size() == 0 判断空,优先用 empty()

empty() 是常量时间,size() 对某些底层容器(比如基于 list 的自定义适配器)可能是 O(n)。虽然 std::dequestd::vectorsize() 都是 O(1),但标准没保证所有适配器都如此。实际写法应统一用:

if (s.empty()) { /* ... */ }
而不是 if (s.size() == 0)。另外,对空栈调用 top()pop() 是未定义行为,务必先判空。

立即学习“C++免费学习笔记(深入)”;

手写栈真正麻烦的不是 push/pop 逻辑,而是异常安全——比如 push() 中内存分配失败时,原有栈状态是否完整。标准库的 std::stack 把这部分压力转移给了底层容器,自己用的时候得心里有数。

相关文章

精彩推荐