【C++初阶】stack的常见操作和模拟实现

在这里插入图片描述

👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:C++航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨


目录

  • 一、stack
    • 1.1 stack的基本概念
    • 1.2 stack的常见操作
      • 1.2.1 常见构造函数
      • 1.2.2 push
      • 1.2.3 pop
      • 1.2.4 empty
      • 1.2.5 top
      • 1.2.6 size
      • 1.2.7 栈的遍历
  • 二、有关栈的力扣经典题
    • 2.1 最小栈
    • 2.2 栈的压入、弹出序列
    • 2.3 逆波兰表达式求值
    • 2.4 用栈实现队列
  • 三、模拟实现stack
    • 3.1 简介
    • 3.2 代码实现

一、stack

1.1 stack的基本概念

在这里插入图片描述

  • stack是一种容器适配器(通过容器转化出来的),是一种先进后出(First in Last Out,简称FILO),它只有一个出口。
  • 容器适配器是一种特殊的容器,它们通过某种方式改变了底层容器的接口或行为。常见的容器适配器还有队列queue和优先队列priority_queue
  • 注意:容器适配器通常会限制对底层容器的访问方式,只有栈顶的元素才能被使用,因此不能有遍历的行为(底层没有设计迭代器)。例如栈和队列都是限制在一端插入或删除元素,优先队列则通过堆来维护元素的有序性。

在这里插入图片描述

1.2 stack的常见操作

在这里插入图片描述

1.2.1 常见构造函数

  • 无参的默认构造(构造空的栈)
// T可以是任意类型
stack<T> _st;
  • 拷贝构造
// _st已知
stack<T> _st(s);

1.2.2 push

功能:将元素val压入stack

1.2.3 pop

功能:stack中尾部的元素弹出

1.2.4 empty

功能:判断stack是否为空,如果为空则返回真,反之。

1.2.5 top

功能:返回栈顶元素

1.2.6 size

功能:返回stack中元素的个数

在这里插入图片描述

1.2.7 栈的遍历

既然栈不支持迭代器,只能打印栈顶的元素,然后出栈。重复以上操作直到栈为空

【代码示例】

#include <iostream>
#include <stack>
using namespace std;int main()
{stack<int> _st;_st.push(1);_st.push(2);_st.push(3);_st.push(4);while (!_st.empty()){cout << _st.top() << ' ';_st.pop();}cout << endl;return 0;
}

【输出结果】

在这里插入图片描述

二、有关栈的力扣经典题

2.1 最小栈

题目链接:点击跳转

【题目描述】

在这里插入图片描述

【思路】

可以定义两个栈,一个栈_st可以用于出栈和入栈操作,另一个栈_min_st用于更新当前_st出栈和入栈的最小值。

对于入栈接口:_st正常入栈。如果_min_st为空,则入栈的值val_st一样;如果不为空,则要比较_min_st当前栈顶的元素是否大于或者等于_st的栈顶元素,如果大于或等于则要入栈。

对于出栈接口:首先要分析_st的栈顶元素是否等于_min_st的栈顶元素,如果相等则要出栈,而_st无论如何都要出栈。

最后,_min_st的栈顶元素则是最小元素的栈。

在这里插入图片描述

【代码实现】

class MinStack {
public:MinStack() {}// 自定义类型会调用默认构造函数// 因此可以不用写void push(int val) {_st.push(val);if (min_st.empty() || val <= min_st.top()){min_st.push(val);}}void pop() {if (_st.top() == min_st.top()){min_st.pop();}_st.pop();}int top() {return _st.top();}int getMin() {return min_st.top();}private:stack<int> _st; stack<int> min_st;
};

2.2 栈的压入、弹出序列

题目链接:点击跳转

【题目描述】

在这里插入图片描述

【思路】

这题直接模拟就行了。

首先定义一个栈_st,并且分别定义变量ij来遍历pushV数组和popV数组,接下来让pushV里的元素一个一个入栈(i++),然后再判定栈顶元素是否等于popV下标为j的元素,如果相等则要出栈。最后如果栈为空,说明栈popV是是pushV弹出的顺序。

要注意pushV可能为空

【代码实现】

class Solution {
public:bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {stack<int> _st;int i = 0; // 遍历pushVint j = 0; // 遍历popVwhile (i < pushV.size()){// 入栈_st.push(pushV[i]);i++;while (!_st.empty() && _st.top() == popV[j]){_st.pop();j++;}}// 如果栈为空,说明匹配return _st.empty();}
};

2.3 逆波兰表达式求值

题目链接:点击跳转

【题目描述】

在这里插入图片描述

【思路】

首先来解释什么是逆波兰表达式求值,逆波兰表达式求值又称后缀表达式,而我们常见的是中缀表达式,例如2 + 1 * 3化成后缀表达式2 1 3 * +

因此我们的思路是:
设计一个栈_st,如果遇到操作数,则将操作数入栈;如果遇到运算符(本题的操作符只有+ - * /),则将两个操作数出栈,但是要注意操作数的顺序,先出栈的是右操作数,出栈后的下一个栈顶元素则是左操作数,对于加法和乘法来说操作数的顺序是无关紧要的,但是对于减法和除法,操作数就要有讲究了。

最后计算出的值继续入栈,直到遍历完毕之后,栈内只有一个元素,则该元素(也就是栈顶)为逆波兰表达式的值。

注意要将string类字符串转化成整型计算,string转化成整型有个函数:atoi

【代码实现】

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> _st;for (auto& x : tokens){if (x != "+" && x != "-" && x != "*" && x != "/"){// 如果不为操作符就入栈_st.push(stoi(x));}else{int right = _st.top();_st.pop();int left = _st.top();_st.pop();// 计算switch(x[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;}}}return _st.top();}
};

2.4 用栈实现队列

题目链接:点击跳转

【题目描述】

在这里插入图片描述

【思路】

举一组数据:1、2、3、4。如果是出栈的话,第一个出的数据是4,而现在要用栈来模拟队列,第一个出的数据必须是1。所以一开先将4个数据全部入栈(push),然后一个个出栈到另一个栈(pop)中,这样1就在栈顶了,对于栈的性质,靠近栈顶的元素先出,这样就能实现栈模拟队列了。

【动图展示】

在这里插入图片描述

【代码实现】

class MyQueue {
public:MyQueue() {}void push(int x) {_st.push(x);}int pop() {if (_queue.empty()){while (!_st.empty()){int val = _st.top();_st.pop();_queue.push(val);}}int front_val = _queue.top();_queue.pop();return front_val;}int peek() {if (_queue.empty()){while (!_st.empty()){int val = _st.top();_st.pop();_queue.push(val);}}return _queue.top();}bool empty() {return _queue.empty() && _st.empty();}private:stack<int> _st;stack<int> _queue;
};

三、模拟实现stack

3.1 简介

在这里插入图片描述

stack是一种容器适配器,容器适配器可以被视为一种包装器,它们通过修改底层容器的接口或行为来实现新的功能。通过使用这些容器适配器,开发者可以方便地在不同场景下使用已有容器的功能,并且无需关心底层容器的具体实现。

其实就是STL中封装好的栈,在使用的时候我们不仅可以指定内部的数据类型,还可以指定内部的容器。不指定容器其实也是可以的,模板参数有一个缺省值,默认是deque

int main()
{//内部容器为vectorstack<int, vector<int>> s1;  //内部容器为list   stack<int, list<int>> s2; //内部为默认容器deque      stack<int> s3;      return 0;
}

3.2 代码实现

注意:指定内部的容器需要有push_backpop_backbacksizeempty等函数接口

#pragma oncenamespace wj
{template<class T, class container = deque<T>>class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}T& top(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:container _con;};
}

【测试代码】

#include <iostream>
#include <deque>
using namespace std;
#include "stack.h"
int main()
{wj::stack<int> _st;_st.push(1);_st.push(2);_st.push(3);_st.push(4);while (!_st.empty()){cout << _st.top() << ' ';_st.pop();}cout << endl;cout << "个数为:" << _st.size() << endl;return 0;
}

【输出结果】

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/88653.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器基础

0x01基础 介绍 可以理解为企业级的电脑&#xff0c;比个人使用的电脑具备更强的配置、性能、可靠性及稳定性。设计工艺和器件全部采用企业级设计&#xff0c;保障7*24小时稳定运行。 演进历史 处理性能 外观 发展方向 分类 按外形分类 按高度分类 按应用分类 按综合能力…

Particle Life粒子生命演化的MATLAB模拟

Particle Life粒子生命演化的MATLAB模拟 0 前言1 基本原理1.1 力影响-吸引排斥行为1.2 距离rmax影响 2 多种粒子相互作用2.1 双种粒子作用2.1 多种粒子作用 3 代码 惯例声明&#xff1a;本人没有相关的工程应用经验&#xff0c;只是纯粹对相关算法感兴趣才写此博客。所以如果有…

Qt 打开文件列表选择文件,实现拖拽方式打开文件

1. 实现打开文件列表选择文件 1.1. 创建 Qt 工程&#xff0c;并添加几个简单控件 这里笔者选用的是 QMainWindow&#xff0c;创建好工程后在 ui 界面设计中添加 QLineEdit、QPushBtton至少这两个控件&#xff0c;如下图摆放。 1.2. 头文件中添加相关操作 在 mainwindow.h 中…

行业追踪,2023-08-29

自动复盘 2023-08-29 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

各个微服务模块之间互相依赖调用的问题

首先是模块之间不能够循环引用&#xff0c;否则会报循环依赖引入的错误。 没有了模块之间的相互依赖&#xff0c;在项目中这两个模块是相互调用的&#xff0c;分别各自定义相应的Feign接口&#xff0c;如下&#xff1a; 最开始写的运行报错的代码如下&#xff1a; FeignCli…

使用ELK(ES+Logstash+Filebeat+Kibana)收集nginx的日志

文章目录 Nginx日志格式修改配置logstash收集nginx日志引入Redis收集日志写入redis从redis中读取日志 引入FilebeatFilebeat简介Filebeat安装和配置 配置nginx转发ES和kibanaELK设置账号和密码 书接上回&#xff1a;《ELK中Logstash的基本配置和用法》 Nginx日志格式修改 默认…

基于MATLAB开发AUTOSAR软件应用层Code mapping专题-part 7 Function callers标签页介绍

不知不觉这个code-mapping专题已经写了6篇文章了,今天是我们这个专题的最后一篇文章了介绍Function callers 这个其实很简单,以前的文章里也有提到CS接口实现两个SWC之间的CS调用,我们在从Code-mapping的角度在说下 首先还是看下模型 我们还记得在simulink里我们用function…

安装Ubuntu服务器、配置网络、并安装ssh进行连接

安装Ubuntu服务器、配置网络、并安装ssh进行连接 1、配置启动U盘2、配置网络3、安装ssh4、修改ssh配置文件5、重启电脑6、在远程使用ssh连接7、其他报错情况 1、配置启动U盘 详见: U盘安装Ubuntu系统详细教程 2、配置网络 详见&#xff1a;https://blog.csdn.net/davidhzq/a…

自动化测试(三):接口自动化pytest测试框架

文章目录 1. 接口自动化的实现2. 知识要点及实践2.1 requests.post传递的参数本质2.2 pytest单元测试框架2.2.1 pytest框架简介2.2.2 pytest装饰器2.2.3 断言、allure测试报告2.2.4 接口关联、封装改进YAML动态传参&#xff08;热加载&#xff09; 2.3 pytest接口封装&#xff…

论文阅读:Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks

前言 要弄清MAML怎么做&#xff0c;为什么这么做&#xff0c;就要看懂这两张图。先说MAML**在做什么&#xff1f;**它是打着Mate-Learing的旗号干的是few-shot multi-task Learning的事情。具体而言就是想训练一个模型能够使用很少的新样本&#xff0c;快速适应新的任务。 定…

安防视频监控/视频集中存储/云存储平台EasyCVR无法播放HLS协议该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

自动化运维:Ansible基础与命令行模块操作

目录 一、理论 1. Ansible 2.部署Ansible自动化运维工具 3.Ansible常用模块 4.hostsinverntory主机清单 二、实验 1.部署Ansible自动化运维工具 2.ansible 命令行模块 3.hostsinverntory主机清单 三、问题 1. ansible远程shell失败 2.组变量查看webservers内主机ip报…