容器适配器(Container Adapter):C++中的专用数据结构工具
目录
容器适配器是C++标准库中的一种特殊容器,它们基于现有的序列容器(如vector、deque、list等)提供特定的接口和行为,而不是独立的容器实现。
一、基本概念
容器适配器可以理解为:
-
设计模式中的适配器:它"包装"了一个现有的容器类,提供一个新的接口
-
受限视图:对底层容器提供特定操作方式的限制性视图
-
接口转换器:将底层容器的接口转换为特定的操作方式
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。

二、主要特点
1、不是独立容器
-
它们依赖于现有的序列容器(如vector、deque等)作为底层存储
-
只是提供了不同的访问方式
2、限制操作接口
-
只暴露特定操作,隐藏底层容器的其他功能
-
例如stack只允许一端操作,queue只允许两端操作
3、默认底层容器
-
stack和queue默认使用deque作为底层容器
-
priority_queue默认使用vector作为底层容器
三、C++中的三种容器适配器
虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为 容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque,比如:
-
stack - 后进先出(LIFO)结构

-
queue - 先进先出(FIFO)结构

-
priority_queue - 优先级队列,元素按优先级顺序出队

四、底层容器选择
容器适配器可以使用不同的底层容器实现:
// stack可以使用vector、deque或list作为底层容器
stack<int, vector<int>> sv; // 基于vector的stack
stack<int, list<int>> sl; // 基于list的stack
// queue可以使用deque或list作为底层容器
queue<int, list<int>> ql; // 基于list的queue
// priority_queue可以使用vector或deque作为底层容器
priority_queue<int, vector<int>> pq;
五、为什么需要容器适配器?
1、提供特定语义
-
明确表达程序意图(如需要栈或队列行为)
-
限制不合适的操作,防止误用
2、简化接口
-
隐藏底层复杂实现,只暴露必要操作
-
使代码更易读和维护
3、灵活性
-
可以根据需要选择不同的底层容器
-
例如需要快速随机访问可以选择vector,需要高效插入删除可以选择list
六、容器适配器与普通容器的区别
| 特性 | 普通容器 (vector, list等) | 容器适配器 (stack, queue等) |
|---|---|---|
| 独立性 | 独立实现 | 依赖底层容器 |
| 接口完整性 | 提供完整容器接口 | 只提供特定操作接口 |
| 迭代器支持 | 支持 | 不支持 |
| 元素访问方式 | 多种方式 | 受限访问方式 |
| 默认构造行为 | 空容器 | 基于默认底层容器构造 |
七、实现原理简析
容器适配器通常通过组合方式实现,例如stack的可能简化实现:
template <class T, class Container = deque<T>>
class stack {
protected:
Container c; // 底层容器
public:
void push(const T& x) { c.push_back(x); }
void pop() { c.pop_back(); }
T& top() { return c.back(); }
// 其他成员函数...
};
八、使用建议
-
默认情况:使用默认底层容器(通常是最优选择)
-
性能考虑:
-
stack如果需要频繁扩容,vector可能更合适
-
queue如果频繁在两端操作,deque是更好选择
-
-
内存考虑:list作为底层容器不会有扩容开销,但内存使用不连续
-
安全考虑:容器适配器限制操作,减少误用可能性
容器适配器通过提供受限但更语义化的接口,使我们在特定场景下能写出更清晰、更安全的代码。
九、通俗易懂解释容器适配器
1、用日常生活比喻
可以把容器适配器想象成"多功能变形玩具":
-
基础玩具:就像乐高积木(相当于C++的vector、deque这些基础容器),你可以自由拼装任何形状
-
变形玩具:就像用乐高积木专门拼成的"手枪"或"汽车"(相当于stack、queue这些容器适配器):
-
它们是用乐高拼成的
-
但只能当"手枪"或"汽车"来玩,不能随便拆改
-
玩法固定(手枪只能射击,汽车只能跑)
-
2、简单来说
容器适配器就是:
-
"戴着面具的容器":它里面其实装着vector/deque/list这些普通容器
-
"限制功能的容器":只让你用特定方式操作(比如栈只能后进先出)
-
"专用工具":像专门的开瓶器,只能开瓶盖不能干别的
3、举个具体例子
想象一个管道:
-
普通容器:像普通水管,两头都能进出水,还能从中间接水
-
stack适配器:像灭火器,只能从顶部压入和弹出(后进先出)
stack<int> s; // 就像一个垂直的管子 s.push(1); // 从顶部放入1 s.push(2); // 再放入2 cout << s.top(); // 只能看到顶部的2 s.pop(); // 只能取出顶部的2 -
queue适配器:像排队通道,后面进前面出(先进先出)
queue<int> q; // 像一个水平管道 q.push(1); // 从尾部放入1 q.push(2); // 放入2 cout << q.front(); // 只能看到前面的1 q.pop(); // 只能取出前面的1
4、为什么要有这种设计?
-
安全性:防止你乱用(就像灭火器设计成只能一种用法,防止误操作)
-
表达意图:一看就知道你要用栈或队列的逻辑
-
灵活性:可以自由选择底层用什么容器实现(就像灭火器可以用钢瓶或铝瓶)
5、一句话总结
容器适配器就是"给普通容器套上特定操作规则的外壳",让它变成专用工具,既保留了底层容器的存储能力,又限制了操作方式。
更多推荐


所有评论(0)