✨✨小新课堂开课了,欢迎欢迎~✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:C++:由浅入深篇
小新的主页:编程版小新-优快云博客
前言:
今天我们来学习stack和queue,虽然stack和queue中也可以存放元素,但在STL中并没有将其划分到容器的行列,而是将其称为容器适配器。我们来深入了解一下stack和queue吧。
一.容器适配器
1.1什么是适配器
适配器是一种设计模式
(
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设
计经验的总结
)
,
该种模式是将一个类的接口转换成客户希望的另外一个接口。

1.2STL标准库中stack和queue的底层结构
虽然
stack
和
queue
中也可以存放元素,但在
STL
中并没有将其划分在容器的行列,而是将其称为
容器适配器
,这是因为
stack
和queue只是对其他容器的接口进行了包装,
STL
中
stack
和
queue
默认
使用
deque
,比如:

1.3deque的简单介绍(了解即可)
1.3.1deque的原理介绍
deque(
双端队列
)
:是一种双开口的
"
连续
"
空间的数据结构
,双开口的含义是:可以在头尾两端
进行插入和删除操作,且时间复杂度为
O(1)
,与
vector
比较,头插效率高,不需要搬移元素;与
list
比较,空间利用率比较高。

deque
并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际
deque
类似于一个
动态的二维数组
,其底层结构如下图所示:

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其
“
整体连续
”
以及随机访问
的假象,落在了
deque
的迭代器身上,
因此
deque
的迭代器设计就比较复杂,如下图所示:
那
deque
是如何借助其迭代器维护其假想连续的结构呢?

1.3.2deque的缺陷
与
vector
比较
,
deque
的优势是:头部插入和删除时,
不需要搬移元素,效率特别高
,而且在
扩
容时,也不需要搬移大量的元素
,因此其效率是必
vector
高的。
与
list
比较
,其底层是连续空间,
空间利用率比较高
,不需要存储额外字段。
但是,
deque
有一个致命缺陷:不适合遍历,因为在遍历时,
deque
的迭代器要频繁的去检测其
是否移动到某段小空间的边界,导致效率低下
,而序列式场景中,可能需要经常遍历,因此
在实
际中,需要线性结构时,大多数情况下优先考虑
vector
和
list
,
deque
的应用并不多,而
目前能看
到的一个应用就是,
STL
用其作为
stack
和
queue
的底层数据结构
。
1.3.3为什么选择deque作为stack和queue的底层默认容器
stack
是一种后进先出的特殊线性数据结构,因此只要具有
push_back()
和
pop_back()
操作的线性
结构,都可以作为
stack
的底层容器,比如
vector
和
list
都可以;
queue
是先进先出的特殊线性数据
结构,只要具有
push_back
和
pop_front
操作的线性结构,都可以作为
queue
的底层容器,比如
list
。但是
STL
中对
stack
和
queue
默认选择
deque
作为其底层容器,主要是因为:
1. stack
和
queue
不需要遍历
(
因此
stack
和
queue
没有迭代器
)
,只需要在固定的一端或者两端进
行操作。
2.
在
stack
中元素增长时,
deque
比
vector
的效率高
(
扩容时不需要搬移大量数据
)
;
queue
中的
元素增长时,deque不仅效率高,而且内存使用率高。
结合了deque的优点,而完美的避开了其缺陷。
总结:把deque理解成是vector和list的缝合机即可。
二.stack的介绍和使用
stack是一种容器适配器,它基于其他标准容器实现特定的数据结构行为。
特点:
1.后进先出(Last In First Out, LIFO)的数据结构。
2.只能在栈顶进行插入和删除操作。
栈的定义:
1.使用默认的适配器定义栈
//使用默认的适配器定义栈 stack<int> s1;
2.使用特定的适配器定义栈
//使用特定的适配器定义栈 stack<int, vector<int>> s2; stack<int, list<int>> s3;
常用操作:
函数说明 | 接口说明 |
stack() | 构造空的栈 |
empty() | 检测stack是否为空 |
size() | 返回stack中元素的个数 |
top() | 返回栈顶元素的引用 |
push() | 将元素val压入stack中 |
pop() | 将stack中尾部的元素弹出 |
void stack01()
{
stack<int, vector<int>> s1;
s1.push(1);
s1.push(2);
s1.push(3);
s1.push(4);//入栈
cout << s1.size() << endl;//4
//获取栈顶元素
cout << s1.top() << endl;//4
s1.pop();//删除栈顶数据
while (!s1.empty())
{
cout << s1.top()<<" ";// 3 2 1
s1.pop();
}
cout << endl;
stack<int,vector<int>> s2;
s2.push(1);
s2.push(2);
s2.swap(s1);//交换
cout << s1.size() << endl;//2
cout << s2.size() << endl;//0
}
三.queue的介绍和使用
queue是一种容器适配器,它基于其他标准容器实现特定的数据结构行为。
特点:
先进先出(First In First Out)的数据结构
只能在队尾进行插入操作,在队首进行删除操作
queue的定义:
1.使用默认的适配器定义队列
//使用默认的适配器定义队列 queue<int> q1;
2.使用特定的适配器定义队列
//使用特定的适配器定义队列 queue<int, list<int>> q2; queue<int, vector<int>>q3;
常用操作:
函数声明 | 接口说明 |
queue() | 构造空的队列 |
empty() | 检测队列是否为空,是返回true,否则返回false |
size() | 返回队列中有效元素的个数 |
front() | 返回队头元素的引用 |
back() | 返回队尾元素的引用 |
push() | 在队尾将元素val入队列 |
pop() | 将队头元素出队列 |
void queue01()
{
queue<int, list<int>>q1;
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);//入队列
cout << q1.size() << endl;//4
//获取队头元素
cout << q1.front() << endl;//1;
//获取队尾数据
cout << q1.back() << endl;//4
q1.pop();//删除队头数据
while (!q1.empty())
{
cout << q1.front() << " ";//2 3 4
q1.pop();
}
cout << endl;
queue<int, list<int>> q2;
q2.push(1);
q2.push(2);
q2.swap(q1);//交换
cout << q1.size() << endl;//2
cout << q2.size() << endl;//0
}
总结:
适配器的概念不好理解,但是我们在自己使用stack和queue的时候还是很好用的。
感谢各位大佬的观看,创作不易,还请各位大佬支持~