前言
本篇文章主要讲解STL中stack和queue的应用及实现,从这两个容器的学习中还会引出一个新的知识------容器适配器。因为stack和queue的实现很简单,所以本文的核心目标还是让你们知道,理解容器适配器以及适配器的设计模式,这里先透露一点内容,即标准库中一般不把stack,queue简单的定义为容器,而是称为容器适配器,具体的原因,我们之后进行讲解。
目录
-
- [一. stack](#一. stack)
- [二. queue](#二. queue)
- [三. 适配器](#三. 适配器)
一. stack
stack的应用
std::stack的基本使用
| 成员函数 | 功能描述 | 时间复杂度 | 代码示例 | 说明 / 效果 |
|---|---|---|---|---|
push(const T& val) |
将元素压入栈顶 | O(1) | s.push(10); s.push(20); |
栈内元素:10, 20(20 在栈顶) |
pop() |
弹出栈顶元素(无返回值,需确保栈非空) | O(1) | s.pop(); |
移除当前栈顶元素(如上例中的 20) |
top() |
返回栈顶元素的可修改引用 | O(1) | s.top() = 100; |
将栈顶元素值修改为 100 |
top() const |
返回栈顶元素的只读引用 | O(1) | int x = s.top(); |
x 获得栈顶元素的值(如 100) |
empty() |
判断栈是否为空 | O(1) | if (!s.empty()) { /* ... */ } |
非空时进入条件分支 |
size() |
返回栈中当前元素个数 | O(1) | cout << s.size(); |
输出元素个数(例如 1) |
swap(stack& other) |
交换两个栈的全部底层内容(C++11) | O(1) | stack<int> s2; s2.push(99); s.swap(s2); |
交换后,s 栈顶为 99,s2 获得原 s 的内数据 |
std::stack在算法题中的应用
题目描述
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
题解
本题的唯一的难点就在于需要在常数的时间内找到栈中最小的元素,那要如何实现呢?首先确定,使用一个变量维护栈中的最小值的方案是不可行的,因为题目还提供了pop的函数接口,这就代表会有数据的删除,当删除的数据刚好是最小值,此时需要再拿到最小值就只能遍历stack了,且不说时间复杂度不是O(1),就是遍历stack都是一个麻烦的操作。
既然不能使用一个变量维护最小值,就要使用一个容器记录最小值,所以我们考虑使用一个栈minst来维护普通栈st中的最小值,使用st.top()就可以拿到最小值。minst的维护逻辑很简单,维护操作分为两个情况:
- push:当st进行插入数据val时,如果此时minst为空,那么此时st中的最小值一定是val,所以stmin也要插入val。这里还有一个情况就是当
val < stmin.top()时,代表此时st中的最小值要更新了,需要将val插入minst。
这里需要注意的是,容器中可能同时存在多个相同的最小值,举个例子,如st = { 2,3,1,2,1,1,1,5 };,此时为了保证删除操作正确,如果val和stmin.top()相等,也需要插入数据。 - pop:当进行删除栈顶数据时,只需要判断st.top()是否和minst.top()相等,如果相等,代表此时删除的是st中的最小值,所以minst也需要进行删除操作。
cpp
class MinStack {
public:
MinStack() {
}
void push(int value) {
st.push(value);
// 如果最小栈为空,或者value小于等于当前栈中的最小值,才将数据插入到minst中
if(minst.empty() || value <= minst.top())
minst.push(value);
}
void pop() {
// 如果删除的值和最小值相同,那minst也要删除栈顶数据
if(st.top() == minst.top())
minst.pop();
st.pop();
}
int top() {
return st.top();
}
int getMin() {
return minst.top();
}
private:
stack<int> st;
stack<int> minst;
};
题目描述
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
题解
逆波兰表达式也称为后缀表达式,而后缀表达式求值是栈的经典应用。因为后缀表达式是将两个需要运算的数字的运算符放在数字的后面,举个例子,如2 3 -就是一个后缀表达式,而它等价于2 - 3。所以给我们一串后缀表达式,要进行求值的关键就是只要遇到运算符号,就找它的前两位数字,然后进行运算得出结果。
因为这里对于数字的运算顺序为:后遇到的数字先计算。所以我们使用栈来存储操作数和操作符,刚好符合这里的计算逻辑。
cpp
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(const auto& e : tokens)
{
if(e == "+" || e == "-" || e == "*" || e == "/")
{
int behind = st.top(); st.pop();
int front = st.top(); st.pop();
switch(e[0])
{
case '+':
st.push(front + behind);
break;
case '-':
st.push(front - behind);
break;
case '*':
st.push(front * behind);
break;
case '/':
st.push(front / behind);
break;
default:
break;
}
}else
{
st.push(stoi(e));
}
}
return st.top();
}
};
stack的模拟实现
我们知道,栈是一种线性结构的容器,看过我在数据结构篇章的栈和队列的文章的就知道,在数据结构阶段,栈的底层是使用一个顺序表实现的(具体原因我在那篇文章中有详细分析),因此,对于stack的模拟实现,我们也使用顺序表作为它的底层。
基于vector的模拟实现的底层也是一个顺序表,那这里对于stack的实现,还是像vector一样重新写一个顺序表然后封装为stack吗?这样太麻烦了,正确的方法是,直接使用vector作为stack底层的容器,简单点说,就是让vector类型的对象做stack的成员变量。
stack的实现的代码如下,可以看到stack的实现的代码量和逻辑和deque的实现简直是天差地别,包括命名空间仅仅只有16行代码就实现完了,究其原因,都是因为直接对vector和vector的成员函数进行复用,所以将stack说成是简约版的vector也不足为过。
cpp
namespace yzx
{
template<class T>
class stack
{
public:
void push(const T& val){ _con.push_back(val); }
void pop(){ _con.pop_back(); }
int& top(){ return _con.back(); }
const int& top() const{ return _con.back(); }
bool empty() const{ return _con.empty(); }
size_t size() const{ return _con.size(); }
private:
vector<T> _con;
};
}
stack模拟实现架构图
#mermaid-svg-nnf0PB7eST5ALGKl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nnf0PB7eST5ALGKl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nnf0PB7eST5ALGKl .error-icon{fill:#552222;}#mermaid-svg-nnf0PB7eST5ALGKl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nnf0PB7eST5ALGKl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nnf0PB7eST5ALGKl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nnf0PB7eST5ALGKl .marker.cross{stroke:#333333;}#mermaid-svg-nnf0PB7eST5ALGKl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nnf0PB7eST5ALGKl p{margin:0;}#mermaid-svg-nnf0PB7eST5ALGKl g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-nnf0PB7eST5ALGKl g.classGroup text .title{font-weight:bolder;}#mermaid-svg-nnf0PB7eST5ALGKl .cluster-label text{fill:#333;}#mermaid-svg-nnf0PB7eST5ALGKl .cluster-label span{color:#333;}#mermaid-svg-nnf0PB7eST5ALGKl .cluster-label span p{background-color:transparent;}#mermaid-svg-nnf0PB7eST5ALGKl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nnf0PB7eST5ALGKl .cluster text{fill:#333;}#mermaid-svg-nnf0PB7eST5ALGKl .cluster span{color:#333;}#mermaid-svg-nnf0PB7eST5ALGKl .nodeLabel,#mermaid-svg-nnf0PB7eST5ALGKl .edgeLabel{color:#131300;}#mermaid-svg-nnf0PB7eST5ALGKl .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-nnf0PB7eST5ALGKl .label text{fill:#131300;}#mermaid-svg-nnf0PB7eST5ALGKl .labelBkg{background:#ECECFF;}#mermaid-svg-nnf0PB7eST5ALGKl .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-nnf0PB7eST5ALGKl .classTitle{font-weight:bolder;}#mermaid-svg-nnf0PB7eST5ALGKl .node rect,#mermaid-svg-nnf0PB7eST5ALGKl .node circle,#mermaid-svg-nnf0PB7eST5ALGKl .node ellipse,#mermaid-svg-nnf0PB7eST5ALGKl .node polygon,#mermaid-svg-nnf0PB7eST5ALGKl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nnf0PB7eST5ALGKl .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl g.clickable{cursor:pointer;}#mermaid-svg-nnf0PB7eST5ALGKl g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-nnf0PB7eST5ALGKl g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-nnf0PB7eST5ALGKl .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-nnf0PB7eST5ALGKl .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-nnf0PB7eST5ALGKl .dashed-line{stroke-dasharray:3;}#mermaid-svg-nnf0PB7eST5ALGKl .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-nnf0PB7eST5ALGKl #compositionStart,#mermaid-svg-nnf0PB7eST5ALGKl .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #compositionEnd,#mermaid-svg-nnf0PB7eST5ALGKl .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #dependencyStart,#mermaid-svg-nnf0PB7eST5ALGKl .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #dependencyStart,#mermaid-svg-nnf0PB7eST5ALGKl .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #extensionStart,#mermaid-svg-nnf0PB7eST5ALGKl .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #extensionEnd,#mermaid-svg-nnf0PB7eST5ALGKl .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #aggregationStart,#mermaid-svg-nnf0PB7eST5ALGKl .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #aggregationEnd,#mermaid-svg-nnf0PB7eST5ALGKl .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #lollipopStart,#mermaid-svg-nnf0PB7eST5ALGKl .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl #lollipopEnd,#mermaid-svg-nnf0PB7eST5ALGKl .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-nnf0PB7eST5ALGKl .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-nnf0PB7eST5ALGKl .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nnf0PB7eST5ALGKl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nnf0PB7eST5ALGKl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nnf0PB7eST5ALGKl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 默认底层容器
可选底层容器
stack
Container _con
push(const T& val)
pop()
top()
empty()
size()
vector
T* _data
size_t _size
size_t _capacity
push_back(const T& val)
pop_back()
back()
back()
empty()
size()
deque
多个缓冲区
中控器管理
push_back(const T& val)
pop_back()
back()
back()
empty()
size()
适配器模式:复用底层容器接口
实现栈的特定功能
二. queue
queue的成员函数
| 成员函数 | 功能描述 | 时间复杂度 | 代码示例 | 说明 / 效果 |
|---|---|---|---|---|
push(const T& val) |
将元素添加到队尾(拷贝构造) | O(1) | q.push(10); q.push(20); |
队列内元素:10, 20(10 在队头,20 在队尾) |
pop() |
弹出队头元素(无返回值,需确保队列非空) | O(1) | q.pop(); |
移除队头元素(移除 10),队列变为 20 |
front() |
返回队头元素的可修改引用 | O(1) | q.front() = 99; |
将当前队头(20)修改为 99 |
front() const |
返回队头元素的只读引用 | O(1) | int x = q.front(); |
x 获得队头元素的值(如 99) |
back() |
返回队尾元素的可修改引用 | O(1) | q.back() = 88; |
将当前队尾(20)修改为 88 |
back() const |
返回队尾元素的只读引用 | O(1) | int y = q.back(); |
y 获得队尾元素的值(如 88) |
empty() |
判断队列是否为空 | O(1) | if (!q.empty()) { /* ... */ } |
非空时进入条件分支 |
size() |
返回队列中当前元素个数 | O(1) | cout << q.size(); |
输出元素个数(例如 1) |
swap(queue& other) |
交换两个队列的全部底层内容(C++11) | O(1) | queue<int> q2; q2.push(77); q.swap(q2); |
交换后,q 队头为 77,q2 获得原 q 的内容 |
queue的模拟实现
在数据结构给queue的定义中,queue也属于是线性表,且因为queue只能尾部插入数据头部删除数据的特性,所以queue的底层也可以复用一个容器来实现,但是如果再继续使用vector作为queue的底层容器,就是一个不明智的选择了。
因为queue的删除数据是从头部删除的,而众所周知,vector在头部数据操作上效率低的让人难以接受,所以queue的底层容器不选择使用vector,而是选择list作为queue的底层容器。
如下代码为queue以list为底层容器的实现,其简洁程度与stack的模拟实现有过之而无不及。
cpp
namespace yzx
{
template<class T>
class queue
{
public:
void push(const T& val){ _con.push_back(val); }
void pop(){ _con.pop_front(); }
T& front(){ return _con.front(); }
T& back(){ return _con.back(); }
const T& front() const { return _con.front(); }
const T& back() const{ return _con.back(); }
size_t size() const{ return _con.size(); }
bool empty() const{ return _con.empty(); }
private:
list<T> _con;
};
}
queue模拟实现架构图
#mermaid-svg-vp7CYos2gr4XuTMO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vp7CYos2gr4XuTMO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vp7CYos2gr4XuTMO .error-icon{fill:#552222;}#mermaid-svg-vp7CYos2gr4XuTMO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vp7CYos2gr4XuTMO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vp7CYos2gr4XuTMO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vp7CYos2gr4XuTMO .marker.cross{stroke:#333333;}#mermaid-svg-vp7CYos2gr4XuTMO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vp7CYos2gr4XuTMO p{margin:0;}#mermaid-svg-vp7CYos2gr4XuTMO g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-vp7CYos2gr4XuTMO g.classGroup text .title{font-weight:bolder;}#mermaid-svg-vp7CYos2gr4XuTMO .cluster-label text{fill:#333;}#mermaid-svg-vp7CYos2gr4XuTMO .cluster-label span{color:#333;}#mermaid-svg-vp7CYos2gr4XuTMO .cluster-label span p{background-color:transparent;}#mermaid-svg-vp7CYos2gr4XuTMO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vp7CYos2gr4XuTMO .cluster text{fill:#333;}#mermaid-svg-vp7CYos2gr4XuTMO .cluster span{color:#333;}#mermaid-svg-vp7CYos2gr4XuTMO .nodeLabel,#mermaid-svg-vp7CYos2gr4XuTMO .edgeLabel{color:#131300;}#mermaid-svg-vp7CYos2gr4XuTMO .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-vp7CYos2gr4XuTMO .label text{fill:#131300;}#mermaid-svg-vp7CYos2gr4XuTMO .labelBkg{background:#ECECFF;}#mermaid-svg-vp7CYos2gr4XuTMO .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-vp7CYos2gr4XuTMO .classTitle{font-weight:bolder;}#mermaid-svg-vp7CYos2gr4XuTMO .node rect,#mermaid-svg-vp7CYos2gr4XuTMO .node circle,#mermaid-svg-vp7CYos2gr4XuTMO .node ellipse,#mermaid-svg-vp7CYos2gr4XuTMO .node polygon,#mermaid-svg-vp7CYos2gr4XuTMO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vp7CYos2gr4XuTMO .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO g.clickable{cursor:pointer;}#mermaid-svg-vp7CYos2gr4XuTMO g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-vp7CYos2gr4XuTMO g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-vp7CYos2gr4XuTMO .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-vp7CYos2gr4XuTMO .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-vp7CYos2gr4XuTMO .dashed-line{stroke-dasharray:3;}#mermaid-svg-vp7CYos2gr4XuTMO .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-vp7CYos2gr4XuTMO #compositionStart,#mermaid-svg-vp7CYos2gr4XuTMO .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #compositionEnd,#mermaid-svg-vp7CYos2gr4XuTMO .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #dependencyStart,#mermaid-svg-vp7CYos2gr4XuTMO .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #dependencyStart,#mermaid-svg-vp7CYos2gr4XuTMO .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #extensionStart,#mermaid-svg-vp7CYos2gr4XuTMO .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #extensionEnd,#mermaid-svg-vp7CYos2gr4XuTMO .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #aggregationStart,#mermaid-svg-vp7CYos2gr4XuTMO .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #aggregationEnd,#mermaid-svg-vp7CYos2gr4XuTMO .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #lollipopStart,#mermaid-svg-vp7CYos2gr4XuTMO .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO #lollipopEnd,#mermaid-svg-vp7CYos2gr4XuTMO .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-vp7CYos2gr4XuTMO .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-vp7CYos2gr4XuTMO .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vp7CYos2gr4XuTMO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vp7CYos2gr4XuTMO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vp7CYos2gr4XuTMO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 常用底层容器
默认底层容器
queue
Container _con
push(const T& val)
pop()
front()
back()
front()
back()
empty()
size()
list
节点结构
头尾指针
push_back(const T& val)
pop_front()
front()
back()
front()
back()
empty()
size()
deque
多个缓冲区
中控器管理
push_back(const T& val)
pop_front()
front()
back()
front()
back()
empty()
size()
适配器模式:复用底层容器接口
实现队列的特定功能
三. 适配器
什么是适配器?
适配器是一种设计模式,其核心理念就是,对同源的东西设计出不同的接口以满足用户不同的需求,举个例子,家用电的电压为220v,但是手机,笔记本,烧水壶的电压却没有那么大,所以,为了适配这些家用电器的电压才产生除了各种不同的充电器,转接器......而这种设计模式就叫做适配器。

图 3-1 适配器模式
适配器模式示意图
#mermaid-svg-UXDaBP5zroi5jmHj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UXDaBP5zroi5jmHj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UXDaBP5zroi5jmHj .error-icon{fill:#552222;}#mermaid-svg-UXDaBP5zroi5jmHj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UXDaBP5zroi5jmHj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UXDaBP5zroi5jmHj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UXDaBP5zroi5jmHj .marker.cross{stroke:#333333;}#mermaid-svg-UXDaBP5zroi5jmHj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UXDaBP5zroi5jmHj p{margin:0;}#mermaid-svg-UXDaBP5zroi5jmHj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UXDaBP5zroi5jmHj .cluster-label text{fill:#333;}#mermaid-svg-UXDaBP5zroi5jmHj .cluster-label span{color:#333;}#mermaid-svg-UXDaBP5zroi5jmHj .cluster-label span p{background-color:transparent;}#mermaid-svg-UXDaBP5zroi5jmHj .label text,#mermaid-svg-UXDaBP5zroi5jmHj span{fill:#333;color:#333;}#mermaid-svg-UXDaBP5zroi5jmHj .node rect,#mermaid-svg-UXDaBP5zroi5jmHj .node circle,#mermaid-svg-UXDaBP5zroi5jmHj .node ellipse,#mermaid-svg-UXDaBP5zroi5jmHj .node polygon,#mermaid-svg-UXDaBP5zroi5jmHj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UXDaBP5zroi5jmHj .rough-node .label text,#mermaid-svg-UXDaBP5zroi5jmHj .node .label text,#mermaid-svg-UXDaBP5zroi5jmHj .image-shape .label,#mermaid-svg-UXDaBP5zroi5jmHj .icon-shape .label{text-anchor:middle;}#mermaid-svg-UXDaBP5zroi5jmHj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UXDaBP5zroi5jmHj .rough-node .label,#mermaid-svg-UXDaBP5zroi5jmHj .node .label,#mermaid-svg-UXDaBP5zroi5jmHj .image-shape .label,#mermaid-svg-UXDaBP5zroi5jmHj .icon-shape .label{text-align:center;}#mermaid-svg-UXDaBP5zroi5jmHj .node.clickable{cursor:pointer;}#mermaid-svg-UXDaBP5zroi5jmHj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UXDaBP5zroi5jmHj .arrowheadPath{fill:#333333;}#mermaid-svg-UXDaBP5zroi5jmHj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UXDaBP5zroi5jmHj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UXDaBP5zroi5jmHj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UXDaBP5zroi5jmHj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UXDaBP5zroi5jmHj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UXDaBP5zroi5jmHj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UXDaBP5zroi5jmHj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UXDaBP5zroi5jmHj .cluster text{fill:#333;}#mermaid-svg-UXDaBP5zroi5jmHj .cluster span{color:#333;}#mermaid-svg-UXDaBP5zroi5jmHj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UXDaBP5zroi5jmHj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UXDaBP5zroi5jmHj rect.text{fill:none;stroke-width:0;}#mermaid-svg-UXDaBP5zroi5jmHj .icon-shape,#mermaid-svg-UXDaBP5zroi5jmHj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UXDaBP5zroi5jmHj .icon-shape p,#mermaid-svg-UXDaBP5zroi5jmHj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UXDaBP5zroi5jmHj .icon-shape .label rect,#mermaid-svg-UXDaBP5zroi5jmHj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UXDaBP5zroi5jmHj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UXDaBP5zroi5jmHj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UXDaBP5zroi5jmHj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 适配器模式结构
客户端 Client
目标接口 Target Interface
适配器 Adapter
被适配者 Adaptee
容器适配器
C++标准库中也涉及到了适配器的设计模式,其中最具代表性的就是容器适配器。前面我们说了,std::stack和std::queue就是容器适配器,那为什么这样说呢?这是因为,C++标准库为std::stack和std::queue提供了一个接口,使得用户可以根据需求自行的选择实现它们的底层容器,如图 3-2,3-3所示。
从图中可以看到,stack和queue都有一个模板参数Container作为它们底层的容器,而C++标准库中为stack和queue设置的默认的底层实现容器时deque,这里和我们上面所想的不一样,这里为什么要使用deque呢?
原因很简单,deque的特性天然就适合作为stack和queue的底层容器。回顾一下deque,我们说deque的优点是头部和尾部的插入删除数据的效率很高,缺点是中间位置的插入删除效率很低,而stack和queue恰好只能在头部或者尾部插入删除数据。因此,使用deque作为stack和queue不仅发挥了deque的优点,同时又避开了deque的缺点,所以说deque就是stack和queue底层容器的首选。

图 3-2 stack的模板参数

图 3-3 queue的模板参数
这里我们根据C++标准库中实现stack和queue的方法,对上面实现的stack和queue进行改造,使得模拟实现的版本也包含适配器的涉及模式,最终代码如下所示。
cpp
namespace yzx
{
template<class T, class Container = deque<T>>
class stack
{
public:
void push(const T& val){ _con.push_back(val); }
void pop(){ _con.pop_back(); }
int& top(){ return _con.back(); }
const int& top() const{ return _con.back(); }
bool empty() const{ return _con.empty(); }
size_t size() const{ return _con.size(); }
private:
Container _con;
};
}
cpp
namespace yzx
{
template<class T, class Container = deque<T>>
class queue
{
public:
void push(const T& val){ _con.push_back(val); }
void pop(){ _con.pop_front(); }
T& front(){ return _con.front(); }
T& back(){ return _con.back(); }
const T& front() const { return _con.front(); }
const T& back() const{ return _con.back(); }
size_t size() const{ return _con.size(); }
bool empty() const{ return _con.empty(); }
private:
Container _con;
};
}
#mermaid-svg-8cj5uB3H2xilRC1Z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8cj5uB3H2xilRC1Z .error-icon{fill:#552222;}#mermaid-svg-8cj5uB3H2xilRC1Z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8cj5uB3H2xilRC1Z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8cj5uB3H2xilRC1Z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8cj5uB3H2xilRC1Z .marker.cross{stroke:#333333;}#mermaid-svg-8cj5uB3H2xilRC1Z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8cj5uB3H2xilRC1Z p{margin:0;}#mermaid-svg-8cj5uB3H2xilRC1Z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z .cluster-label text{fill:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z .cluster-label span{color:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z .cluster-label span p{background-color:transparent;}#mermaid-svg-8cj5uB3H2xilRC1Z .label text,#mermaid-svg-8cj5uB3H2xilRC1Z span{fill:#333;color:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z .node rect,#mermaid-svg-8cj5uB3H2xilRC1Z .node circle,#mermaid-svg-8cj5uB3H2xilRC1Z .node ellipse,#mermaid-svg-8cj5uB3H2xilRC1Z .node polygon,#mermaid-svg-8cj5uB3H2xilRC1Z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8cj5uB3H2xilRC1Z .rough-node .label text,#mermaid-svg-8cj5uB3H2xilRC1Z .node .label text,#mermaid-svg-8cj5uB3H2xilRC1Z .image-shape .label,#mermaid-svg-8cj5uB3H2xilRC1Z .icon-shape .label{text-anchor:middle;}#mermaid-svg-8cj5uB3H2xilRC1Z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8cj5uB3H2xilRC1Z .rough-node .label,#mermaid-svg-8cj5uB3H2xilRC1Z .node .label,#mermaid-svg-8cj5uB3H2xilRC1Z .image-shape .label,#mermaid-svg-8cj5uB3H2xilRC1Z .icon-shape .label{text-align:center;}#mermaid-svg-8cj5uB3H2xilRC1Z .node.clickable{cursor:pointer;}#mermaid-svg-8cj5uB3H2xilRC1Z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8cj5uB3H2xilRC1Z .arrowheadPath{fill:#333333;}#mermaid-svg-8cj5uB3H2xilRC1Z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8cj5uB3H2xilRC1Z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8cj5uB3H2xilRC1Z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8cj5uB3H2xilRC1Z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8cj5uB3H2xilRC1Z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8cj5uB3H2xilRC1Z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8cj5uB3H2xilRC1Z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8cj5uB3H2xilRC1Z .cluster text{fill:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z .cluster span{color:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8cj5uB3H2xilRC1Z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8cj5uB3H2xilRC1Z rect.text{fill:none;stroke-width:0;}#mermaid-svg-8cj5uB3H2xilRC1Z .icon-shape,#mermaid-svg-8cj5uB3H2xilRC1Z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8cj5uB3H2xilRC1Z .icon-shape p,#mermaid-svg-8cj5uB3H2xilRC1Z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8cj5uB3H2xilRC1Z .icon-shape .label rect,#mermaid-svg-8cj5uB3H2xilRC1Z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8cj5uB3H2xilRC1Z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8cj5uB3H2xilRC1Z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8cj5uB3H2xilRC1Z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 容器适配器示例
Stack使用者
Stack接口
push/pop/top
Queue使用者
Queue接口
push/pop/front/back
Stack适配器
Queue适配器
底层容器
vector/deque/list
底层容器
deque/list
vector: 顺序表
deque: 双端队列
list: 链表
deque: 双端队列
list: 链表