目录
4.5 为什么选择deque作为stack和queue的底层默认容器?
1.stack
1.1 stack的介绍
堆栈是一种容器适配器,专门设计用于在后进先出环境(后进先出)中运行,其中元素仅从容器的一端插入和提取。
cplusplus.com/reference/stack/stack/?kw=stack
1.2 stack的使用
前文中也接触过过Stack和queue,有了stl提供的Stack和queue,我们就不再需要自己实现栈和队列,大大方便了我们利用Stack和queue解决问题。
1.3 OJ 题目
借助两个栈实现最小栈
class MinStack {
public:
MinStack()
{}
void push(int val)
{
_st.push(val);
if(_minst.empty() || val <= _minst.top())
{
_minst.push(val);
}
}
void pop() {
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;
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pushV int整型vector
* @param popV int整型vector
* @return bool布尔型
*/
bool IsPopOrder(vector<int>& pushV, vector<int>& popV)
{
size_t popi=0;
stack<int> st;
for(auto& e : pushV)
{
st.push(e);
while(!st.empty() && st.top() == popV[popi])
{
st.pop();
popi++;
}
}
return st.empty();
}
};
class Solution {
public:
int evalRPN(vector<string>& tokens)
{
stack<int> s;
for (size_t i = 0; i < tokens.size(); ++i)
{
string& str = tokens[i];
// str为数字
if (!("+" == str || "-" == str || "*" == str || "/" == str))
{
s.push(atoi(str.c_str()));
}
else
{
// str为操作符
int right = s.top();
s.pop();
int left = s.top();
s.pop();
switch (str[0])
{
case '+':
s.push(left + right);
break;
case '-':
s.push(left - right);
break;
case '*':
s.push(left * right);
break;
case '/':
// 题目说明了不存在除数为0的情况
s.push(left / right);
break;
}
}
}
return s.top();
}
};
class MyQueue {
public:
MyQueue()
{
}
void push(int x)
{
_push.push(x);
}
int pop()
{
if(_pop.empty())
{
while(!_push.empty())
{
int front = _push.top();
_pop.push(front);
_push.pop();
}
}
int x = _pop.top();
_pop.pop();
return x;
}
int peek()
{
if(_pop.empty())
{
while(!_push.empty())
{
int front = _push.top();
_pop.push(front);
_push.pop();
}
}
return _pop.top();
}
bool empty()
{
return _push.empty() && _pop.empty();
}
private:
stack<int> _push;
stack<int> _pop;
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
1.4 stack的模拟实现
从栈的接口中可以看出,栈实际是一种特殊的vector,因此使用vector完全可以模拟实现stack。
#include<vector>
namespace sy
{
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;
};
}
2.queue
2.1 queue的介绍
队列是一种 容器适配器 ,专门用于在FIFO上下文( 先进先出 )中操作,其中从容器一端插入元
素,另一端提取元素。

2.2 queue的使用
2.3 OJ 题目
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> vv;
int levelsize=0;//当前层数个数,控制数据一层一层出
queue<TreeNode*> q;
if(root)
{
q.push(root);
levelsize=1;
}
while(!q.empty())
{
vector<int> v;
while(levelsize--)
{
TreeNode* front= q.front();
v.push_back(front->val);
q.pop();
if(front->left)
{
q.push(front->left);
}
if(front->right)
{
q.push(front->right);
}
}
//当前层出完,下一层都进队列了,队列的size就是下一层的数据
levelsize=q.size();
vv.push_back(v);
}
return vv;
}
};
class MyStack {
public:
MyStack() {
}
void push(int x)
{
if(!q1.empty())
{
q1.push(x);
}
else
{
q2.push(x);
}
}
int pop()
{
int top;
if (!q1.empty())
{
// 将q1中除最后一个元素外的所有元素转移到q2
while (q1.size() > 1) {
q2.push(q1.front());
q1.pop();
}
top = q1.front();
q1.pop();
}
else {
// 将q2中除最后一个元素外的所有元素转移到q1
while (q2.size() > 1)
{
q1.push(q2.front());
q2.pop();
}
top = q2.front();
q2.pop();
}
return top;
}
int top() {
if(!q1.empty())
{
return q1.back();
}
else{
return q2.back();
}
}
bool empty() {
return q1.empty() && q2.empty();
}
private:
queue<int> q1;
queue<int> q2;
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
2.4 queue的模拟实现
因为queue的接口中存在头删和尾插,因此使用vector来封装效率太低,故可以借助list来模拟实
现queue。
#include <list>
namespace sy
{
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;
};
}
3.容器适配器
3.1 什么是适配器
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设
计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。
3.2 STL标准库中stack和queue的底层结构
虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为
容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认
使用deque,比如:

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

4.2 deque的使用
和之前学过的string,vector相关接口类似。
4.3 deque剖析
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个
动态的二维数组,其底层结构如下图所示:

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


4.4 deque的缺陷
与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩
容时,也不需要搬移大量的元素,因此其效率是必vector高的。
与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。
但是,deque有一个致命缺陷: 不适合遍历 ,因为在遍历时,deque的迭代器要频繁的去检测其
是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此 在实
际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看
到的一个应用就是, STL用其作为stack和queue的底层数据结构 。
4.5 为什么选择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的优点,而完美的避开了其缺陷。
4.6 STL标准库中对于stack和queue的模拟实现
4.6.1 stack.h
#pragma once
#include<deque>
namespace sy
{
template<class T, class Container = deque<T>>
class stack
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_back();
}
const T& top() const
{
return _con.back();
}
size_t size() const
{
return _con.size();
}
bool empty() const
{
return _con.empty();
}
private:
Container _con;
};
}
4.6.2 queue.h
#pragma once
#include<deque>
namespace sy
{
template<class T, class Container = deque<T>>
class queue
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
}
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;
};
}
5.priority_queue
5.1 priority_queue介绍
cplusplus.com/reference/queue/priority_queue/#google_vignette
priority_queue 是 C++ 标准库中的一种容器适配器,基于堆数据结构实现,用于高效管理具有优先级的元素。默认情况下,元素按从大到小的顺序排列(大顶堆),但可以通过自定义比较器调整排序方式。
- 底层实现:通常基于 vector 或 deque 实现,使用堆算法维护优先级。
- 时间复杂度:插入和删除操作的时间复杂度为 O(log n),访问顶部元素为 O(1)。
- 默认排序:
std::less<T>
导致大顶堆(最大值在顶部),可通过std::greater<T>
改为小顶堆。
5.1.2 priority_queue的使用
priority_queue - C++ Reference
如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。
#include <iostream>
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
using namespace std;
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);
}
friend ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
void TestPriorityQueue()
{
// 大堆,需要用户在自定义类型中提供<的重载
priority_queue<Date> q1;
q1.push(Date(2025, 10, 29));
q1.push(Date(2025, 10, 28));
q1.push(Date(2025, 10, 30));
cout << q1.top() << endl;
// 如果要创建小堆,需要用户提供>的重载
priority_queue<Date, vector<Date>, greater<Date>> q2;
q2.push(Date(2025, 10, 29));
q2.push(Date(2025, 10, 28));
q2.push(Date(2025, 10, 30));
cout << q2.top() << endl;
}
int main()
{
TestPriorityQueue();
return 0;
}
//运行结果:
//2025 - 10 - 30
//2025 - 10 - 28
5.2 仿函数介绍(简单)
仿函数:本质是一个类,这个类重载operator(),它的对象可以像函数一样使用,使用时候需要包含<functional>。
template<class T>
class Less
{
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
class Greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
5.2.1 使用
#include <iostream>
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
using namespace std;
void TestPriorityQueue()
{
// 默认情况下,创建的是大堆,其底层按照小于号比较
vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };
priority_queue<int> q1;
for (auto& e : v)
q1.push(e);
cout << q1.top() << endl;//9
// 如果要创建小堆,将第三个模板参数换成greater比较方式
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
cout << q2.top() << endl;//0
// 如果要创建大堆,将第三个模板参数换成less比较方式
//priority_queue<int, vector<int>, less<int>> q2(v.begin(), v.end());
}
int main()
{
TestPriorityQueue();
return 0;
}
5.3 priority_queue 模拟实现
5.3.1 priority_queue.h
#pragma once
#include<vector>
template<class T>
class Less
{
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
class Greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
namespace sy
{
// 默认是大堆
template<class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
public:
void AdjustUp(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
void AdjustDown(int parent)
{
// 先假设左孩子小
size_t child = parent * 2 + 1;
Compare com;
while (child < _con.size()) // child >= n说明孩子不存在,调整到叶子了
{
// 找出小的那个孩子
//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
++child;
}
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
const T& top()
{
return _con[0];
}
size_t size() const
{
return _con.size();
}
bool empty() const
{
return _con.empty();
}
private:
Container _con;
};
}
5.4 OJ 使用
215. 数组中的第K个最大元素 - 力扣(LeetCode)
class Solution {
public:
int findKthLargest(vector<int>& nums, int k)
{
// 将数组中的元素先放入优先级队列中
priority_queue<int> p(nums.begin(), nums.end());
// 将优先级队列中前k-1个元素删除掉
for(int i= 0; i < k-1; ++i)
{
p.pop();
}
return p.top();
}
};
class Solution
{
public:
int minmumNumberOfHost(int n, vector<vector<int> >& startEnd)
{
sort(startEnd.begin(), startEnd.end());
priority_queue<int, vector<int>, greater<int>> heap; // 创建⼀个⼩根堆
heap.push(startEnd[0][1]); // 先把第⼀个区间放进去
for(int i = 1; i < n; i++) // 处理剩下的区间
{
int a = startEnd[i][0], b = startEnd[i][1];
if(a >= heap.top()) // 没有重叠
{
heap.pop();
heap.push(b);
}
else // 有重叠
{
heap.push(b); // 重新安排⼀个⼈
}
}
return heap.size();
}
};
5.5 test.cpp
#include<iostream>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
#include"Stack.h"
#include"Queue.h"
#include"PriorityQueue.h"
int main()
{
//sy::stack<int, list<int>> st;
sy::stack<int, vector<int>> st;
// 类模板实例化时,按需实例化,使用哪些成员函数就实例化哪些,不会全实例化
st.push(1);
st.push(2);
st.push(3);
st.push(4);
cout << st.top() << endl;
st.pop();
//sy::queue<int, list<int>> q;
sy::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
cout << q.front() << endl;
q.pop();
return 0;
}
void test_op1()
{
srand(time(0));
const int N = 1000000;
deque<int> dq;
vector<int> v;
for (int i = 0; i < N; ++i)
{
auto e = rand() + i;
v.push_back(e);
dq.push_back(e);
}
int begin1 = clock();
sort(v.begin(), v.end());
int end1 = clock();
int begin2 = clock();
sort(dq.begin(), dq.end());
int end2 = clock();
printf("vector:%d\n", end1 - begin1);
printf("deque:%d\n", end2 - begin2);
}
void test_op2()
{
srand(time(0));
const int N = 1000000;
deque<int> dq1;
deque<int> dq2;
for (int i = 0; i < N; ++i)
{
auto e = rand() + i;
dq1.push_back(e);
dq2.push_back(e);
}
int begin1 = clock();
sort(dq1.begin(), dq1.end());
int end1 = clock();
int begin2 = clock();
// 拷贝到vector
vector<int> v(dq2.begin(), dq2.end());
sort(v.begin(), v.end());
dq2.assign(v.begin(), v.end());
int end2 = clock();
printf("deque sort:%d\n", end1 - begin1);
printf("deque copy vector sort, copy back deque:%d\n", end2 - begin2);
}
int main()
{
test_op2();
return 0;
}
int main()
{
//priority_queue<int> pq;
sy::priority_queue<int, vector<int>, Greater<int>> pq;
//sy::priority_queue<int> pq;
pq.push(4);
pq.push(1);
pq.push(5);
pq.push(7);
pq.push(9);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
return 0;
}
//仿函数:本质是一个类,这个类重载operator(),他的对象可以像函数一样使用
//template<class T>
//class Less
//{
//public:
// bool operator()(const T& x, const T& y)
// {
// return x < y;
// }
//};
//
//template<class T>
//class Greater
//{
//public:
// bool operator()(const T& x, const T& y)
// {
// return x > y;
// }
//};
//< 升序
//> 降序
template<class Compare>
void BubbleSort(int* a, int n, Compare com)
{
for (int j = 0; j < n; j++)
{
// 单趟
int flag = 0;
for (int i = 1; i < n - j; i++)
{
//if (a[i] < a[i - 1])
if (com(a[i], a[i - 1]))
{
swap(a[i - 1], a[i]);
flag = 1;
}
}
if (flag == 0)
{
break;
}
}
}
int main()
{
Less<int> LessFunc;
Greater<int> GreaterFunc;
// 函数对象
cout << LessFunc(1, 2) << endl;
cout << LessFunc.operator()(1, 2) << endl;
int a[] = { 9,1,2,5,7,4,6,3 };
BubbleSort(a, 8, LessFunc);
BubbleSort(a, 8, GreaterFunc);
BubbleSort(a, 8, Less<int>());
BubbleSort(a, 8, Greater<int>());
return 0;
}
//运行结果
//1
//1