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

🔥个人主页:胡萝卜3.0****

📖个人专栏:************************************************************************************************************************************************************************************************************************************************************《C语言》、《数据结构》 、《C++干货分享》、LeetCode&牛客代码强化刷题****************************************************************************************************************************************************************************************************************************************************************

⭐️人生格言:不试试怎么知道自己行不行


🎥胡萝卜3.0🌸的简介:


目录

[一. 先搞懂基础:Stack 与 Queue 的核心特性](#一. 先搞懂基础:Stack 与 Queue 的核心特性)

二、栈(Stack):受限的"单口管道"操作

[2.1 核心特性:](#2.1 核心特性:)

[2.2 stack核心接口使用](#2.2 stack核心接口使用)

[2.2.1 创建stack对象](#2.2.1 创建stack对象)

[2.2.2 常用接口](#2.2.2 常用接口)

三、队列(Queue):先进先出的公平性规则

[3.1 核心特性:](#3.1 核心特性:)

[3.2 核心接口使用](#3.2 核心接口使用)

[3.2.1 创建queue对象](#3.2.1 创建queue对象)

[3.2.2 常用接口](#3.2.2 常用接口)

四、实战训练题

[4.1 最小栈](#4.1 最小栈)

[4.2 栈的压入、弹出序列](#4.2 栈的压入、弹出序列)

[4.3 逆波兰表达式求值](#4.3 逆波兰表达式求值)

[4.4 二叉树的层序遍历](#4.4 二叉树的层序遍历)


一. 先搞懂基础:Stack 与 Queue 的核心特性

在写代码前,首先要明确两者的 "数据访问规则"------ 这是它们区别于其他容器的关键:

|-------|-------------|-----------------|
| 容器 | 核心规则 | 访问特性 |
| stack | 后进先出(LIFO) | 仅能访问"栈顶"元素 |
| queue | 先进先出( FIFO) | 仅能访问"队头"和"堆尾"元素 |

两者的共同特性是:不支持下标访问和迭代器

二、栈(Stack):受限的"单口管道"操作

2.1 核心特性:

  • 访问规则:只能从"栈顶"添加或删除元素(最后入栈的元素最先出栈)
  • 适用场景:函数调用栈,表达式求值等。

参考文档:stack - C++ Reference

2.2 stack核心接口使用

2.2.1 创建stack对象

这里就很直接上代码演示~~

cpp 复制代码
#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()

创建一个空的栈

cpp 复制代码
void testStack1()
{
	//定义栈:默认存储int类型,底层依赖deque实现
	stack<int> st1;

	//可指定底层容器(如vector、list)
	stack<int, vector<int>> st2;
	stack<int, list<int>> st3;
}
  • push()

将数据压入栈中

cpp 复制代码
void testStack1()
{	
	stack<int> st1;
	//压栈
	st1.push(1);
	st1.push(2);
	st1.push(3);
	st1.push(4);
	st1.push(5);
}
  • top()

取栈顶元素

cpp 复制代码
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()

出栈

cpp 复制代码
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();//打印结果:4
	cout << ret << endl;
}
  • size()

求出栈中的有效数据个数

cpp 复制代码
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

cpp 复制代码
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对象
cpp 复制代码
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()

从队尾入队列

cpp 复制代码
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()

从队头出数据

cpp 复制代码
void testQueue1()
{
	queue<int> q;
	//入队
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	q.push(5);
	//出队
	q.pop();
}
  • front()

返回队头元素的引用

cpp 复制代码
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()

返回队尾元素的引用

cpp 复制代码
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()

求出有效数据个数

cpp 复制代码
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()

判断队列是否为空

cpp 复制代码
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. 最小栈

  • 题目描述:
  • 解题思路:
  • 代码演示:
cpp 复制代码
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

  • 解题思路:
  • 代码演示:
cpp 复制代码
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)

  • 题目描述:
  • 解题思路:
  • 代码演示:
cpp 复制代码
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:将整型字符转成整型int
                st.push(stoi(e));
            }
        }
        return st.top();
    }
};

4.4 二叉树的层序遍历

  • 题目链接

102. 二叉树的层序遍历 - 力扣(LeetCode)

  • 题目描述:
  • 解题思路:

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

  • 代码演示:
cpp 复制代码
/**
 * 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;
    }
};
相关推荐
祁同伟.6 小时前
【OJ】二叉树的经典OJ题
数据结构·c++·算法·容器·stl
mit6.8246 小时前
list
c++
满天星83035776 小时前
【C++/STL】哈希表的模拟实现+封装
c++·哈希算法·散列表
骁的小小站9 小时前
Verilator 和 GTKwave联合仿真
开发语言·c++·经验分享·笔记·学习·fpga开发
旭意12 小时前
C++蓝桥杯之结构体10.15
开发语言·c++
颜颜yan_12 小时前
UU远程——让工作、学习、娱乐跨设备无缝衔接,“远程”更像“身边”
学习·娱乐·远程工作
深思慎考13 小时前
调用百度云语音识别服务——实现c++接口识别语音
c++·语音识别·百度云
YJlio14 小时前
Process Monitor 学习笔记(5.24):工具栏参考与高效快捷键指南
笔记·学习·php
deng-c-f14 小时前
Linux C/C++ 学习日记(30):协程(一):同步和异步、协程的简要介绍、用户态CPU调度的实现
学习·协程·同步/异步