C++ STL | 容器适配器

30 阅读3分钟

C++ STL 容器适配器详解

——栈、队列、优先队列的使用与底层原理


📌 什么是容器适配器(Container Adapters)?

在 C++ STL 中,容器适配器不是独立的数据结构,而是基于已有容器(如 dequevectorlist)封装出的新接口,以提供特定的访问逻辑(如 LIFO、FIFO、按优先级访问)。

STL 提供了三种标准容器适配器:

适配器行为默认底层容器
stack后进先出(LIFO)deque
queue先进先出(FIFO)deque
priority_queue按优先级出队(最大堆/最小堆)vector

关键特点

  • 不支持迭代器(不能遍历)
  • 只能通过特定接口访问元素(如 top()push()pop()
  • 可自定义底层容器(需满足特定要求)

1️⃣ stack(栈)

基本操作

#include <stack>
using namespace std;

stack<int> s;
s.push(10);      // 入栈
s.push(20);
cout << s.top(); // 访问栈顶 → 20
s.pop();         // 弹出栈顶(无返回值)
cout << s.size(); // 元素个数
cout << s.empty(); // 是否为空

自定义底层容器

// 使用 vector 作为底层
stack<int, vector<int>> s1;

// 使用 list 作为底层(较少见)
stack<int, list<int>> s2;

⚠️ 要求:底层容器必须支持 back(), push_back(), pop_back() —— 所以 vectordequelist 都可以。


2️⃣ queue(队列)

基本操作

#include <queue>

queue<int> q;
q.push(1);       // 入队
q.push(2);
cout << q.front(); // 队首 → 1
cout << q.back();  // 队尾 → 2
q.pop();           // 出队(无返回值)

自定义底层容器

// 必须使用支持 push_back 和 pop_front 的容器
queue<int, deque<int>> q1;  // 默认
queue<int, list<int>> q2;   // list 也支持
// queue<int, vector<int>> ❌ 错误!vector 没有 pop_front()

3️⃣ priority_queue(优先队列)

本质是一个堆(heap) ,默认是最大堆(最大的元素在顶部)。

基本用法(最大堆)

priority_queue<int> pq; // 默认:最大堆
pq.push(10);
pq.push(30);
pq.push(20);
cout << pq.top(); // → 30(最大值)
pq.pop();         // 移除30

最小堆实现

// 方法1:使用 greater<int>
priority_queue<int, vector<int>, greater<int>> min_pq;

// 方法2:存负数(不推荐)
priority_queue<int> pq;
pq.push(-10); pq.push(-20);
cout << -pq.top(); // 得到最小正数

自定义结构体的优先级

struct Person {
    string name;
    int age;
};

// 方式1:重载 < 运算符(注意:最大堆,所以“年龄大”的优先级高)
bool operator<(const Person& a, const Person& b) {
    return a.age < b.age; // 注意:这里 < 表示 a 优先级低于 b
}

// 方式2:使用仿函数(更灵活)
struct CompareAge {
    bool operator()(const Person& a, const Person& b) {
        return a.age > b.age; // 注意:这里 > 表示 a 优先级更低(用于最小堆)
    }
};

priority_queue<Person, vector<Person>, CompareAge> pq;

🔍 重要提示
priority_queue 的比较函数逻辑是:

  • 如果 comp(a, b) == true,则 b 的优先级高于 a
  • 所以最小堆用 greater<T>(即 a > b 时 b 更小,应优先)

🔧 底层容器选择建议

适配器推荐底层容器原因
stackdeque(默认)或 vectorvector 内存连续,deque 扩容更高效
queuedeque(默认)支持两端高效操作,list 也可但内存开销大
priority_queuevector(默认)堆通常用数组实现,vector 最合适

⚠️ 常见误区

  1. pop() 不返回值

    int x = s.pop(); // ❌ 错误!pop() 返回 void
    // 正确做法:
    int x = s.top(); s.pop();
    
  2. priority_queue 是最大堆,不是最小堆
    想要最小堆必须显式指定 greater<T>

  3. 不能遍历容器适配器
    没有 begin() / end(),无法用 for-each 或算法库。

  4. 底层容器不可直接访问
    适配器封装了底层容器,你无法拿到内部的 dequevector


✅ 总结:何时使用哪个适配器?

场景选择
函数调用、括号匹配、表达式求值stack
BFS、任务调度、缓冲区queue
Top-K 问题、Dijkstra 算法、任务按优先级处理priority_queue

💡 记住:容器适配器是“接口包装器”,它们让已有容器表现出新的行为,复用而不重复造轮子,这正是 STL 设计哲学的体现!

掌握这三类适配器,你就能高效解决大多数需要栈、队列或堆的算法问题!