深入理解栈与队列:核心特性与实战应用

🔥个人主页:胡萝卜3.0
📖个人专栏: 《C语言》、《数据结构》 、《C++干货分享》、LeetCode&牛客代码强化刷题
⭐️人生格言:不试试怎么知道自己行不行
🎥胡萝卜3.0🌸的简介:


目录
一. 先搞懂基础:Stack 与 Queue 的核心特性
二、栈(Stack):受限的“单口管道”操作
2.1 核心特性:
2.2 stack核心接口使用
2.2.1 创建stack对象
2.2.2 常用接口
三、队列(Queue):先进先出的公平性规则
3.1 核心特性:
3.2 核心接口使用
3.2.1 创建queue对象
3.2.2 常用接口
四、实战训练题
4.1 最小栈
4.2 栈的压入、弹出序列
4.3 逆波兰表达式求值
4.4 二叉树的层序遍历
一. 先搞懂基础:Stack 与 Queue 的核心特性
在写代码前,首先要明确两者的 “数据访问规则”—— 这是它们区别于其他容器的关键:
| 容器 | 核心规则 | 访问特性 |
| stack | 后进先出(LIFO) | 仅能访问“栈顶”元素 |
| queue | 先进先出( FIFO) | 仅能访问“队头”和“堆尾”元素 |
两者的共同特性是:不支持下标访问和迭代器
二、栈(Stack):受限的“单口管道”操作
2.1 核心特性:
- 访问规则:只能从"栈顶"添加或删除元素(最后入栈的元素最先出栈)
- 适用场景:函数调用栈,表达式求值等。

参考文档:stack - C++ Reference
2.2 stack核心接口使用
2.2.1 创建stack对象
这里就很直接上代码演示~~
#include<iostream>
#include<stack>
#include<vector>
#include<list>
using namespace std;
void testStack1()
{//定义栈:默认存储int类型,底层依赖deque实现stack<int> st1;//可指定底层容器(如vector、list)stack<int, vector<int>> st2;stack<int, list<int>> st2;
}
stack 是一个容器适配器,我们可以根据需求选择最合适的底层容器。
-
选择
std::vector:可能获得更好的缓存局部性,但动态扩展时可能需要重新分配内存。 -
选择
std::deque(默认):首尾插入删除效率都高,不需要大量的内存重新分配。 -
选择
std::list:在中间插入删除效率高(虽然栈用不到),但内存开销稍大。
2.2.2 常用接口
| 函数说明 | 接口说明 |
| stack() | 构造空的栈 |
| push() | 将元素val压入stack中 |
| pop() | 出栈操作 |
| top() | 返回栈顶元素的引用 |
| empty() | 检测stack是否为空 |
| size() | 返回stack中元素的个数 |
这些接口的使用很简单,我们快速演示一下:
- stack()
创建一个空的栈
void testStack1()
{//定义栈:默认存储int类型,底层依赖deque实现stack<int> st1;//可指定底层容器(如vector、list)stack<int, vector<int>> st2;stack<int, list<int>> st3;
}
- push()
将数据压入栈中
void testStack1()
{ stack<int> st1;//压栈st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);
}
- top()
取栈顶元素
void testStack1()
{ stack<int> st1;//压栈st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);//取栈顶元素int ret = st1.top();cout << ret << endl;
}
- pop()
出栈
void testStack1()
{ stack<int> st1;//压栈st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);//取栈顶元素int ret = st1.top();cout << ret << endl;//打印结果:5//出栈st1.pop();//取栈顶元素ret = st1.top();//打印结果:4cout << ret << endl;
}
- size()
求出栈中的有效数据个数
void testStack1()
{ stack<int> st1;//压栈st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);//求出有效数据个数size_t _size = st1.size();cout << _size << endl;
}
- empty()
判断栈是否为空,栈为空返回true,栈不为空返回false
void testStack1()
{ stack<int> st1;//压栈st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);//判断栈是否为空bool ret = st1.empty();cout << ret << endl;//输出结果为0,说明栈不为空
}
三、队列(Queue):先进先出的公平性规则
3.1 核心特性:
- 访问规则:从"队尾"添加元素,从"队头"删除元素(最先入队的元素最先出队)
- 适用场景:任务调度(如打印队列)、消息队列、广度优先搜索(BFS)等

参考文档:queue - C++ Reference
3.2 核心接口使用
3.2.1 创建queue对象
void testQueue1()
{//定义队列:默认底层依赖deque实现queue<int> q;//可指定底层容器(如list,不能使用vector,std::vector 不支持 pop_front() 操作)queue<int, list<int>> q2;
}
3.2.2 常用接口
| 函数声明 | 接口说明 |
| empty() | 检测队列是否为空,是返回true,否则返回false |
| size() | 返回队列中有效元素的个数 |
| front() | 返回队头元素的引用 |
| back() | 返回队尾元素的引用 |
| push() | 在队尾将元素val入队列 |
| pop() | 将队头元素出队列 |
- push()
从队尾入队列
void testQueue1()
{queue<int> q;//入队q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);while (!q.empty()){cout << q.front() << " ";q.pop();}
}
- pop()
从队头出数据
void testQueue1()
{queue<int> q;//入队q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);//出队q.pop();
}
- front()
返回队头元素的引用
void testQueue1()
{queue<int> q;//入队q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);//返回队头元素的引用int _front = q.front();cout << _front << endl;
}
- back()
返回队尾元素的引用
void testQueue1()
{queue<int> q;//入队q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);//返回队尾元素的引用int _back = q.back();cout << _back << endl;
}
- size()
求出有效数据个数
void testQueue1()
{queue<int> q;//入队q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);//有效数据个数size_t _size = q.size();cout << _size << endl;
}
- empty()
判断队列是否为空
void testQueue1()
{queue<int> q;//入队q.push(1);q.push(2);q.push(3);q.push(4);q.push(5);//判断队列是否为空bool ret = q.empty();cout << ret << endl;
}
ok,stack和queue的使用就说到这里,接下来我们来做几个题
四、实战训练题
4.1 最小栈
题目链接:
155. 最小栈
- 题目描述:

- 解题思路:

- 代码演示:
class MinStack {
public://这里的构造不用写,默认生成的构造会去调用stack中的构造MinStack() {}void push(int val) {_str.push(val);if(_minstr.empty()||_str.top()<=_minstr.top()){_minstr.push(val);}}void pop() {if(_str.top()==_minstr.top()){_minstr.pop();}_str.pop();}int top() {return _str.top();}int getMin() {return _minstr.top();}private:stack<int> _str;stack<int> _minstr;
};
4.2 栈的压入、弹出序列
题目链接:
栈的压入、弹出序列_牛客题霸_牛客网
- 题目描述:

简单来说:就是判断出栈顺序是否和提供的出栈顺序是相同的,相同返回true,不相同返回false
- 解题思路:

- 代码演示:
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param pushV int整型vector * @param popV int整型vector * @return bool布尔型*/bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {size_t posh=0,posp=0;stack<int> st;while(posh < pushV.size()){st.push(pushV[posh]);while(!st.empty()&&st.top()==popV[posp]){st.pop();posp++;}//跳出循环,说明不相等了,继续入栈posh++;}return st.empty();}
};
4.3 逆波兰表达式求值
题目链接:
150. 逆波兰表达式求值 - 力扣(LeetCode)
- 题目描述:


- 解题思路:

- 代码演示:
class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> st;for(auto& e:tokens){if(e=="+"||e=="-"||e=="*"||e=="/"){//操作符,进行运算操作int right=st.top();st.pop();int left=st.top();st.pop();switch(e[0]){case '+':st.push(left+right);break;case '-':st.push(left-right);break;case '*':st.push(left*right);break;case '/':st.push(left/right);break; }}else{//操作数//stoi:将整型字符转成整型intst.push(stoi(e));}}return st.top();}
};
4.4 二叉树的层序遍历
题目链接:
102. 二叉树的层序遍历 - 力扣(LeetCode)
- 题目描述:

- 解题思路:
每次只出当前层的元素,出之前把它的左右孩子插入栈中,等到当前层的出完出去之后更新levelSize,此时刚好等于现在栈中的元素个数。

- 代码演示:
/*** 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) {queue<TreeNode*> q;size_t levelSize;if(root){q.push(root);levelSize=1;}vector<vector<int>> vv;//一层一层的出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);}}vv.push_back(v);levelSize=q.size();}return vv;}
};
