C++ STL 栈、队列与优先级队列:从入门到模拟实现
栈(stack)、队列(queue)、优先级队列(priority_queue)是 C++ STL 中非常经典的容器适配器,它们不直接存储数据,而是封装底层容器实现特定数据结构规则。本文从基础用法、经典场景到模拟实现,一次性讲透这三个核心组件。
一、栈(stack):后进先出的线性结构
1.1 栈的核心特性
栈遵循后进先出(LIFO) 原则,仅允许在栈顶进行插入、删除、访问操作,不支持遍历与中间位置操作。
1.2 栈的常用接口
| 函数 | 功能 |
|---|---|
| stack() | 构造空栈 |
| empty() | 判断栈是否为空 |
| size() | 返回栈中元素个数 |
| top() | 返回栈顶元素引用 |
| push(val) | 元素入栈(栈顶) |
| pop() | 栈顶元素出栈 |
1.3 最小栈(经典扩展)
最小栈支持在 O(1) 时间内获取栈中最小值,核心思路是用两个栈:一个存原始数据,一个存最小值。
cpp
class MinStack {
public:
void push(int x) {
_elem.push(x);
if (_min.empty() || x <= _min.top()) {
_min.push(x);
}
}
void pop() {
if (_min.top() == _elem.top()) {
_min.pop();
}
_elem.pop();
}
int top() { return _elem.top(); }
int getMin() { return _min.top(); }
private:
std::stack<int> _elem; // 存储原始数据
std::stack<int> _min; // 存储最小值
};
1.4 栈的模拟实现
栈仅需尾插、尾删操作,底层可封装 vector/deque/list,默认用 deque。
cpp
#include <vector>
namespace man{
template<class T>
class stack {
public:
stack() {}
void push(const T& x) { _c.push_back(x); }
void pop() { _c.pop_back(); }
T& top() { return _c.back(); }
const T& top() const { return _c.back(); }
size_t size() const { return _c.size(); }
bool empty() const { return _c.empty(); }
private:
std::vector<T> _c;
};
}
二、队列(queue):先进先出的线性结构
2.1 队列的核心特性
队列遵循先进先出(FIFO) 原则,队尾入队、队头出队,同样不支持遍历与中间操作。
2.2 队列的常用接口
| 函数 | 功能 |
|---|---|
| queue() | 构造空队列 |
| empty() | 判断队列是否为空 |
| size() | 返回队列有效元素个数 |
| front() | 返回队头元素引用 |
| back() | 返回队尾元素引用 |
| push(val) | 队尾入队 |
| pop() | 队头出队 |
2.3 队列的模拟实现
队列需要尾插、头删,vector 头删效率低,推荐封装 list/deque。
cpp
#include <list>
namespace man {
template<class T>
class queue {
public:
queue() {}
void push(const T& x) { _c.push_back(x); }
void pop() { _c.pop_front(); }
T& back() { return _c.back(); }
const T& back() const { return _c.back(); }
T& front() { return _c.front(); }
const T& front() const { return _c.front(); }
size_t size() const { return _c.size(); }
bool empty() const { return _c.empty(); }
private:
std::list<T> _c;
};
}
三、优先级队列(priority_queue):堆的封装
3.1 优先级队列核心特性
优先级队列本质是堆 ,默认是大顶堆(堆顶为最大值),支持快速获取极值,插入/删除均为 O(logN) 复杂度。
3.2 优先级队列常用接口
| 函数 | 功能 |
|---|---|
| priority_queue() | 构造空优先级队列 |
| empty() | 判断是否为空 |
| top() | 返回堆顶元素(最大/最小值) |
| push(val) | 插入元素并调整堆 |
| pop() | 删除堆顶元素并调整堆 |
3.3 大堆与小堆创建
cpp
#include <vector>
#include <queue>
#include <functional>
void TestPriorityQueue() {
vector<int> v{3,2,7,6,0,4,1,9,8,5};
// 默认大顶堆
priority_queue<int> q1(v.begin(), v.end());
// 小顶堆(第三个参数为 greater)
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
}
3.4 自定义类型适配
自定义类型需要重载 < 或 > 运算符,才能用于优先级队列。
cpp
class Date {
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year), _month(month), _day(day) {}
bool operator<(const Date& d) const {
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d) const {
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
private:
int _year, _month, _day;
};
四、容器适配器深度解析
4.1 什么是容器适配器
适配器是一种设计模式,将已有类的接口转换为目标接口,stack/queue/priority_queue 都是 STL 容器适配器,不独立存储数据,只封装底层容器。
4.2 STL 默认底层容器
- stack:默认
deque - queue:默认
deque - priority_queue:默认
vector+ 堆算法
4.3 deque(双端队列)简介
deque 是分段连续 的双开口结构,支持 O(1) 头尾插删,扩容无需大量搬移数据,但不适合频繁遍历。
4.4 为什么 stack/queue 默认用 deque
- stack/queue 不需要遍历,避开 deque 遍历效率低的缺陷;
- deque 头尾操作效率高,扩容成本远低于 vector,内存利用率优于 list;
- 完美适配 stack(尾插尾删)、queue(尾插头删)的操作需求。
4.5 通用版模拟实现(支持自定义底层容器)
栈通用实现
cpp
#include <deque>
namespace bite {
template<class T, class Con = deque<T>>
class stack {
public:
stack() {}
void push(const T& x) { _c.push_back(x); }
void pop() { _c.pop_back(); }
T& top() { return _c.back(); }
const T& top() const { return _c.back(); }
size_t size() const { return _c.size(); }
bool empty() const { return _c.empty(); }
private:
Con _c;
};
}
队列通用实现
cpp
#include <deque>
namespace man {
template<class T, class Con = deque<T>>
class queue {
public:
queue() {}
void push(const T& x) { _c.push_back(x); }
void pop() { _c.pop_front(); }
T& back() { return _c.back(); }
const T& back() const { return _c.back(); }
T& front() { return _c.front(); }
const T& front() const { return _c.front(); }
size_t size() const { return _c.size(); }
bool empty() const { return _c.empty(); }
private:
Con _c;
};
}
五、总结
- stack:后进先出,仅操作栈顶,底层封装 vector/deque;
- queue:先进先出,队尾入队、队头出队,底层封装 list/deque;
- priority_queue:堆结构,默认大顶堆,底层默认 vector;
- 三者均为容器适配器,STL 默认用 deque 作为 stack/queue 底层,兼顾效率与内存。