当前位置: 首页 > news >正文

HJ50-四则运算:栈的运用、中缀表达式转后缀表达式并计算结果

文章目录

  • 题目
  • 一、分析
      • 1.1表达式预处理
      • 1.2中缀表达式转后缀
      • 1.3 后缀表达式计算结果
  • 二、答案


题目

在这里插入图片描述


一、分析

通过利用栈将中缀表达式转换为后缀表达式,在根据后缀表达式计算运算结果。由于包含负数操作数的情况,并且操作数位数不固定为1,因此,需要对输入的表达式进行预处理,将操作数和操作符进行分离,并且将大括号和中括号统一为小括号。

1.1表达式预处理

/// <summary>
/// 预处理表达式
/// </summary>
/// <param name="data">中缀表达式</param>
/// <returns>表达式</returns>
std::vector<std::string>  pretreat(const std::string& data)
{std::string value = data;//->处理括号for (int i = 0; i < value.size(); i++){if (value[i] == '[' || value[i] == '{') value[i] = '(';if (value[i] == ']' || value[i] == '}') value[i] = ')';}//->处理负数,并将运算符与运算数拆分开value = '(' + value + ')';	int index = -1;std::vector<std::string> content;for (int i = 0; i < value.size(); i++){//->负数操作数的情况if (value[i] == '-' && (i - 1) >= 0 && value[i - 1] == '(' && (i + 1) < value.size() && value[i + 1] >= '0' && value[i + 1] <= '9'){index = i;continue;}//->非负数操作数else if (value[i] >= '0' && value[i] <= '9' && index == -1){index = i;}if ((value[i] < '0' || value[i] > '9') && index != -1){content.push_back(value.substr(index, i - index));index = -1;}if ((value[i] < '0' || value[i] > '9') && index == -1){content.push_back(value.substr(i, 1));}}return content;
}

1.2中缀表达式转后缀

1.2.1 对于中缀表达式A+B*(C-D)-E/F转后后缀表达式时,栈中数据变化情况如下。

1.2.2 栈内和栈外操作符的优先级如下。

std::map<std::string, int> isp = { {"#",0}, {"(",1},  {"*",5},  {"/",5},  {"+",3},  {"-",3},  {")",6} };//->栈内操作符的优先级
std::map<std::string, int> icp = { {"#",0}, {"(",6},  {"*",4},  {"/",4},  {"+",2},  {"-",2},  {")",1} };//->栈外操作符的优先级

1.2.3 代码逻辑伪代码如下,可根据此变化设计代码逻辑。

扫描项项类型动作栈变化输出
0“#”进栈#
1A操作数#A
2+操作符isp[“#”] < icp[“+”],进栈#+A
3B操作数#+AB
4*操作符isp[“+”] < icp[“*”],进栈#+*AB
5(操作符isp[“*”] < icp[“(”],进栈#+*(AB
6C操作数#+*(ABC
7-操作符isp[“(”] < icp[“-”],进栈#+*(-ABC
8D操作数#+*(-ABCD
9)操作符isp[“-”] >icp[“)”],退栈#+*(ABCD-
”(“ == “)”,退栈#+*ABCD-
10-操作符isp[“*”] > icp[“-”],退栈#+ABCD-*
isp[“+”] > icp[“-”],退栈#ABCD-*+
isp[“#”] < icp[“-”],进栈#-ABCD-*+
11E操作数#-ABCD-*+E
12/操作符isp[“-”] < icp[“/”],进栈#-/ABCD-*+E
13F操作数#-/ABCD-*+EF
14#操作符isp[“/”] > icp[“#”],退栈#-ABCD-*+EF/
操作符isp[“-”] > icp[“#”],退栈#ABCD-*+EF/-
结束
/// <summary>
/// 判断是否是操作数
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
bool isDigit(std::string& value)
{if (value.empty())return false;return value.back() >= '0' && value.back() <= '9';
}/// <summary>
/// 将中缀表达式转换为后缀表达式
/// </summary>
/// <param name="data">中缀表达式</param>
/// <returns>后缀表达式</returns>
std::vector<std::string> postfix(std::vector<std::string>& content)
{//->定义栈内操作符和栈外操作符的优先级std::map<std::string, int> isp = { {"#",0}, {"(",1},  {"*",5},  {"/",5},  {"+",3},  {"-",3},  {")",6} };//->栈内操作符的优先级std::map<std::string, int> icp = { {"#",0}, {"(",6},  {"*",4},  {"/",4},  {"+",2},  {"-",2},  {")",1} };//->栈外操作符的优先级content.push_back("#");int index = 0;std::vector<std::string> expression;std::string item1 = "#", item2, item3;std::stack<std::string> stack;stack.push(item1);item1 = content[index];index++;while (!stack.empty() && item1 != "#"){if (isDigit(item1)){expression.push_back(item1);item1 = content[index];index++;}else{item2 = stack.top();if (isp[item2] < icp[item1]){stack.push(item1);item1 = content[index];index++;}else if (isp[item2] > icp[item1]){expression.push_back(stack.top());item3 = stack.top();stack.pop();}else{std::string item = stack.top();stack.pop();if (item == "("){item1 = content[index];index++;}}}}return expression;
}

1.3 后缀表达式计算结果

1.3.1 计算后缀表达式ABCD-*+EF/-栈中元素变化情况,逻辑如下。

扫描项项类型动作栈中内容
1栈置空
2A操作数进栈A
3B操作数进栈AB
4C操作数进栈ABC
5D操作数进栈ABCD
6-操作符D、C退栈,计算C-D,结果R1进栈ABR1
7*操作符R1、B退栈,计算B*R1,结果R2进栈BR2
8+操作符R2、B退栈,计算A+R2,结果R3进栈R3
9E操作数进栈R3E
10F操作数进栈R3EF
11/操作符F、E退栈,计算E/F,结果R4进栈R3R4
12-操作符R4、R3退栈。计算R3-R4,结果R5进栈R5
/// <summary>
/// 根据后缀表达式计算结果
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
float calculator(std::vector<std::string>& expression)
{std::stack<float> values;for (int i = 0; i < expression.size(); i++){std::string value = expression[i];if (isDigit(value)){values.push(std::atoi(value.c_str()));}else{float value1 = values.top(); values.pop();float value2 = values.top(); values.pop();switch (value[0]){case '+': values.push(value2 + value1); break;case '-':  values.push(value2 - value1); break;case '*': values.push(value2 * value1); break;case '/': values.push(value2 / value1); break;default:break;}}}return values.top();
}

二、答案

#include  <iostream>
#include <stack>
#include <string>
#include <vector>
#include <map>/// <summary>
/// 判断是否是操作数
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
bool isDigit(std::string& value)
{if (value.empty())return false;return value.back() >= '0' && value.back() <= '9';
}/// <summary>
/// 将中缀表达式转换为后缀表达式
/// </summary>
/// <param name="data">中缀表达式</param>
/// <returns>后缀表达式</returns>
std::vector<std::string> postfix(std::vector<std::string>& content)
{//->定义栈内操作符和栈外操作符的优先级std::map<std::string, int> isp = { {"#",0}, {"(",1},  {"*",5},  {"/",5},  {"+",3},  {"-",3},  {")",6} };//->栈内操作符的优先级std::map<std::string, int> icp = { {"#",0}, {"(",6},  {"*",4},  {"/",4},  {"+",2},  {"-",2},  {")",1} };//->栈外操作符的优先级content.push_back("#");int index = 0;std::vector<std::string> expression;std::string item1 = "#", item2, item3;std::stack<std::string> stack;stack.push(item1);item1 = content[index];index++;while (!stack.empty() && item1 != "#"){if (isDigit(item1)){expression.push_back(item1);item1 = content[index];index++;}else{item2 = stack.top();if (isp[item2] < icp[item1]){stack.push(item1);item1 = content[index];index++;}else if (isp[item2] > icp[item1]){expression.push_back(stack.top());item3 = stack.top();stack.pop();}else{std::string item = stack.top();stack.pop();if (item == "("){item1 = content[index];index++;}}}}return expression;
}/// <summary>
/// 预处理表达式
/// </summary>
/// <param name="data">中缀表达式</param>
/// <returns>表达式</returns>
std::vector<std::string>  pretreat(const std::string& data)
{std::string value = data;//->处理括号for (int i = 0; i < value.size(); i++){if (value[i] == '[' || value[i] == '{') value[i] = '(';if (value[i] == ']' || value[i] == '}') value[i] = ')';}//->处理负数,并将运算符与运算数拆分开value = '(' + value + ')';	int index = -1;std::vector<std::string> content;for (int i = 0; i < value.size(); i++){//->负数操作数的情况if (value[i] == '-' && (i - 1) >= 0 && value[i - 1] == '(' && (i + 1) < value.size() && value[i + 1] >= '0' && value[i + 1] <= '9'){index = i;continue;}//->非负数操作数else if (value[i] >= '0' && value[i] <= '9' && index == -1){index = i;}if ((value[i] < '0' || value[i] > '9') && index != -1){content.push_back(value.substr(index, i - index));index = -1;}if ((value[i] < '0' || value[i] > '9') && index == -1){content.push_back(value.substr(i, 1));}}return content;
}/// <summary>
/// 根据后缀表达式计算结果
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
float calculator(std::vector<std::string>& expression)
{std::stack<float> values;for (int i = 0; i < expression.size(); i++){std::string value = expression[i];if (isDigit(value)){values.push(std::atoi(value.c_str()));}else{float value1 = values.top(); values.pop();float value2 = values.top(); values.pop();switch (value[0]){case '+': values.push(value2 + value1); break;case '-':  values.push(value2 - value1); break;case '*': values.push(value2 * value1); break;case '/': values.push(value2 / value1); break;default:break;}}}return values.top();
}int main()
{std::string data;std::cin >> data;std::vector<std::string> content = pretreat(data);std::vector<std::string> expression = postfix(content);std::cout << calculator(expression);return 0;
}

相关文章:

HJ50-四则运算:栈的运用、中缀表达式转后缀表达式并计算结果

文章目录 题目一、分析1.1表达式预处理1.2中缀表达式转后缀1.3 后缀表达式计算结果 二、答案 题目 一、分析 通过利用栈将中缀表达式转换为后缀表达式&#xff0c;在根据后缀表达式计算运算结果。由于包含负数操作数的情况&#xff0c;并且操作数位数不固定为1&#xff0c;因此…...

C++编程:实现简单的高精度时间日志记录小程序

0. 概述 为了检查是否存在系统时间跳变&#xff0c;本文使用C实现了一个简单的高精度时间日志记录小程序。该程序能够每隔指定时间&#xff08;默认40毫秒&#xff09;记录一次系统时间到文件中&#xff0c;并具备以下功能&#xff1a; 自定义时间间隔和文件名&#xff1a;通…...

QQ机器人搭建

使用QQ官方机器人Python SDK和三方框架搭建QQ群聊机器人 文章目录 使用QQ官方机器人Python SDK和三方框架搭建QQ群聊机器人前言编写机器人代码机器人监听群聊进行文字回复机器人监听群聊进行图片回复机器人监听群聊进行文件发送机器人监听群聊进行视频发送机器人监听群聊进行语…...

flink设置保存点和恢复保存点

增加了hdfs package com.qyt;import org.apache.flink.api.java.functions.KeySelector; import org.apache.flink.api.java.tuple.Tuple2;import org.apache.flink.runtime.state.storage.FileSystemCheckpointStorage;import org.apache.flink.streaming.api.datastream.Dat…...

使用python获取百度一下,热搜TOP数据详情

一、查找对应链接 # 警告&#xff1a;以下代码仅供学习和交流使用&#xff0c;严禁用于任何违法活动。 # 本代码旨在帮助理解和学习编程概念&#xff0c;不得用于侵犯他人权益或违反法律法规的行为。 1、打开百度页面 百度一下&#xff0c;你就知道 2、点击F12 或 右键鼠标…...

Go conc库学习与使用

文章目录 主要功能和特点conc 的安装典型使用场景示例代码并行执行多个 Goroutines错误处理限制并发 Goroutines 数量使用 context.Context 进行任务控制 常见问题1. **任务中发生 panic**原因&#xff1a;解决方法&#xff1a; 2. **conc.Group 重复调用 Wait()**原因&#xf…...

大模型prompt先关

对于未出现的任务&#xff0c;prompt编写技巧&#xff1a; 1、假设你是资深的摘要生成专家&#xff0c;根据提供的内容&#xff0c;总结对应的摘要信息。请生成一个指令&#xff0c;指令中带有一个使用例子。直接提供给大型模型以执行此任务。 2、基于大模型提供的内容再进行二…...

尚品汇-自动化部署-Jenkins的安装与环境配置(五十六)

目录&#xff1a; 自动化持续集成 &#xff08;1&#xff09;环境准备 &#xff08;2&#xff09;初始化 Jenkins 插件和管理员用户 &#xff08;3&#xff09;工作流程 &#xff08;4&#xff09;配置 Jenkins 构建工具 自动化持续集成 互联网软件的开发和发布&#xf…...

【尚跑】2024铜川红色照金半程马拉松赛,大爬坡152安全完赛

1、赛事背景 2024年9月22日8点&#xff0c;2024铜川红色照金半程马拉松赛于照金1933广场鸣枪起跑&#xff01; 起跑仪式上&#xff0c;6000位选手们合唱《歌唱祖国》&#xff0c;熟悉的旋律响彻陕甘边革命根据地照金纪念馆前&#xff0c;激昂的歌声凝聚心中不变的热爱。随着国…...

WPS中让两列数据合并的方法

有这样一个需求&#xff0c;就是把A列数据和B列数据进行合并&#xff08;空单元格略过&#xff09;具体实现效果如图下&#xff1a; 该如何操作呢&#xff1f; 首先在新的一列第一个单元格中输入公式"A1&B1" 然后回车&#xff0c;就出现了两列单元格数据合并的效…...

使用yum为centos系统安装软件以及使用(包含阿里云yum源配置)

centos系统配置阿里云yum源 因为centos7官方停止维护&#xff0c;自带yum源用不了了&#xff0c;所以可以更换成阿里云yum源 方法&#xff1a; 使用root权限执行以下语句 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo CentOS…...

《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析

目录 一、透视变换 1、什么是透视变换 2、操作步骤 1&#xff09;选择透视变换的源图像和目标图像 2&#xff09;确定透视变换所需的关键点 3&#xff09;计算透视变换的变换矩阵 4&#xff09;对源图像进行透视变换 5&#xff09;对变换后的图像进行插值处理 二、轮廓检测…...

Linux 线程互斥

前言 对于初学线程的伙伴来讲&#xff0c;多线程并发访问导致的数据不一致问题&#xff0c;总是让人陷入怀疑&#xff0c;很多人只是给你说加锁&#xff01;但没有人告诉你为什么&#xff1f;本篇博客将详解&#xff01; 目录 前言 一、线程互斥 • 为什么票会出现负数的情…...

【Redis 源码】6AOF持久化

1 AOF功能说明 aof.c 文件是 Redis 中负责 AOF&#xff08;Append-Only File&#xff09;持久化的核心文件。AOF 持久化通过记录服务器接收到的每个写命令来实现数据的持久化。这样&#xff0c;在 Redis 重启时&#xff0c;可以通过重放这些命令来恢复数据。 2 AOF相关配置 a…...

6.MySQL基本查询

目录 表的增删查改Insert&#xff08;插入&#xff09;插入替换插入替换2 Retrieve&#xff08;查找&#xff09;SELECT 列全列查找指定列查询查询字段为表达式为查询结果指定别名结果去重 WHERE 条件order by子句筛选分页结果 Update&#xff08;更新&#xff09;delete&#…...

Linux字符设备驱动开发

Linux 字符设备驱动开发是内核模块开发中的一个重要部分&#xff0c;主要用于处理字节流数据设备&#xff08;如串口、键盘、鼠标等&#xff09;。字符设备驱动的核心任务是定义如何与用户空间程序交互&#xff0c;通常通过一组文件操作函数进行。这些函数会映射到 open、read、…...

HTML5+JavaScript绘制闪烁的网格错觉

HTML5JavaScript绘制闪烁的网格错觉 闪烁的网格错觉&#xff08;scintillating grid illusion&#xff09;是一种视觉错觉&#xff0c;通过简单的黑白方格网格和少量的精心设计&#xff0c;能够使人眼前出现动态变化的效果。 闪烁的栅格错觉&#xff0c;是一种经典的视觉错觉…...

每日OJ题_牛客_拼三角_枚举/DFS_C++_Java

目录 牛客_拼三角_枚举/DFS 题目解析 C代码1 C代码2 Java代码 牛客_拼三角_枚举/DFS 拼三角_枚举/DFS 题目解析 简单枚举&#xff0c;不过有很多种枚举方法&#xff0c;这里直接用简单粗暴的枚举方式。 C代码1 #include <iostream> #include <algorithm> …...

[uni-app]小兔鲜-01项目起步

项目介绍 效果演示 技术架构 创建项目 HBuilderX创建 下载HBuilderX编辑器 HBuilderX/创建项目: 选择模板/选择Vue版本/创建 安装插件: 工具/插件安装/uni-app(Vue3)编译器 vue代码不能直接运行在小程序环境, 编译插件帮助我们进行代码转换 绑定微信开发者工具: 指定微信开…...

安全的价值:构建现代企业的基础

物理安全对于组织来说并不是事后才考虑的问题&#xff1a;它是关键的基础设施。零售商、医疗保健提供商、市政当局、学校和所有其他类型的组织都依赖安全系统来保障其人员和场所的安全。 随着安全技术能力的不断发展&#xff0c;许多组织正在以更广泛的视角看待他们的投资&am…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...