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

news2024/9/28 20:55:33

文章目录

  • 题目
  • 一、分析
      • 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法篇】二叉树类(3)(笔记)

目录 一、Leetcode 题目 1. 二叉树的最近公共祖先 2. 二叉搜索树的最近公共祖先 &#xff08;1&#xff09;递归法 &#xff08;2&#xff09;迭代法 3. 二叉搜索树中的插入操作 &#xff08;1&#xff09;递归法 &#xff08;2&#xff09;迭代法 4. 删除二叉搜索树中…

时间序列LSTM实现

这个代码参考了时间序列预测模型实战案例(三)(LSTM)(Python)(深度学习)时间序列预测(包括运行代码以及代码讲解)_lstm预测模型-CSDN博客 结合我之前所学的lstm-seq2seq里所学习到的知识对其进行预测 import time import numpy as np import pandas as pd import torch import…

革命题材网络电影《突进夹金山》将于10月上线

“长征万里险&#xff0c;最忆夹金山”。这座雪山不仅见证了红军战士们的英勇与牺牲&#xff0c;也成为了中国革命历史上的一座重要里程碑。 革命题材网络电影《突进夹金山》&#xff0c;作为四川省2024年度重点影视剧项目以及纪念红军长征90周年献礼的红色作品&#xff0c;由谢…

死磕P7: JVM类加载那些事儿,一起探知类的前世今生(二)

这是「死磕P7」系列第 006 篇文章&#xff0c;欢迎大家来跟我一起 死磕 100 天&#xff0c;争取在 2025 年来临之际&#xff0c;给自己一个交代。 接上篇&#xff0c;上一篇介绍了 JVM 类加载过程及类的生命周期&#xff0c;回顾一下&#xff1a; 死磕P7: JVM类加载那些事儿&a…

周文强聚焦助学育人,爱心图书室项目圆满完成

日前&#xff0c;一场充满爱心与希望的公益活动在四川甘孜州乡城县尼斯寄宿制小学拉开帷幕。这次名为“520爱心图书室”的公益活动&#xff0c;旨在通过捐赠图书的方式&#xff0c;支持基层青少年的阅读成长。作为此次活动的积极参与者&#xff0c;周文强不仅向学校捐赠了价值1…

python 高效读取多个geojson 写入一个sq3(Sqlite) 、效率提高90%+

1.问题缘由&#xff1a; 由于工作需求&#xff0c;需要将多个&#xff08;总量10G&#xff09;geojson文件写入到sq3库&#xff0c;众所周知&#xff0c;sqlite 不支持多线程写入&#xff0c;那该怎么办呢&#xff0c;在网上也查了很多策略&#xff0c;都没有达到立竿见影的效果…

甄选范文“论分布式存储系统架构设计”,软考高级论文,系统架构设计师论文

论文真题 分布式存储系统(Distributed Storage System)通常将数据分散存储在多台独立的设备上。传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。分布式存储系统采用可扩展的…

车辆重识别(去噪扩散概率模型)论文阅读2024/9/27

[2] Denoising Diffusion Probabilistic Models 作者&#xff1a;Jonathan Ho Ajay Jain Pieter Abbeel 单位&#xff1a;加州大学伯克利分校 摘要&#xff1a; 我们提出了高质量的图像合成结果使用扩散概率模型&#xff0c;一类潜变量模型从非平衡热力学的考虑启发。我们的最…

linux驱动设备程序(内核层、应用层)

一、linux驱动程序 1、分类 字符设备&#xff08;驱动&#xff09;、块设备&#xff08;驱动&#xff09;、网络设备&#xff08;驱动&#xff09;。 2、核心 应用程序运行在用户空间&#xff08;3G&#xff09;&#xff1b;<系统调用>——><陷入>——>&…

正则表达式在过滤交换机lldp信息的应用举例

#include <iostream> #include <string> #include <regex> #include <vector> #include <unordered_map> #include <sstream> #include <unistd.h> // For usleep// 假设存在的 LOG_INFO 和 LOG_WARNING 函数 #define LOG_INFO(...)…

17.第二阶段x86游戏实战2-线程发包和明文包

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

基于docker-compose部署openvas

目录 0.部署openvas 1.编辑docker-compose文件 2.运行compose 3.访问openvas 4.openvas扫描 5.创建任务 6.点击Task Wizard ​编辑 7.输入通讯的IP地址 8.下载报告 9.下载完成 0.部署openvas 1.编辑docker-compose文件 vim docker-compose.yaml version: 3service…

《论文阅读》 用于产生移情反应的迭代联想记忆模型 ACL2024

《论文阅读》 用于产生移情反应的迭代联想记忆模型 ACL2024 前言简介任务定义模型架构Encoding Dialogue InformationCapturing Associated InformationPredicting Emotion and Generating Response损失函数问题前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦…

通信工程学习:什么是MAI多址干扰

MAI:多址干扰 MAI多址干扰(Multiple Access Interference)是无线通信领域,特别是在码分多址(CDMA)系统中,一个关键的干扰现象。以下是对MAI多址干扰的详细解释: 一、定义 多址干扰是指在CDMA系统中,由于多个用户的信号在时域和频域上是混叠的,从而导…

区块链可投会议CCF C--FC 2025 截止10.8 附录用率

Conference&#xff1a;Financial Cryptography and Data Security (FC) CCF level&#xff1a;CCF C Categories&#xff1a;network and information security Year&#xff1a;2025 Conference time&#xff1a;14–18 April 2025, Miyakojima, Japan 录用率&#xff1…

阿里云oss配置

阿里云oss配置 我们可以使用阿里云的对象存储服务来存储图片&#xff0c;首先我们要注册阿里云的账号登录后可以免费试用OSS服务。 之后我们打开控制台&#xff0c;选择对象存储服务&#xff0c;就看到我们下面的画面&#xff1a; 我们点击创建Bucket,之后就会出现如下图界面…

退出系统接口代码开发

退出系统不需要传入参数 请求过滤404的错误--请求次数监听这些都不需要更改 从controller层开始开发代码&#xff0c;因为每个接口都需要增加接口防刷拦截&#xff0c;不然会恶意攻击&#xff0c;所以在这里增加退出系统接口防刷拦截&#xff1b;并退出系统接口没有header和t…

图像分割(九)—— Mask Transfiner for High-Quality Instance Segmentation

Mask Transfiner for High-Quality Instance Segmentation Abstract1. Intrudouction3. Mask Transfiner3.1. Incoherent Regions3.2. Quadtree for Mask RefinementDetection of Incoherent Regions四叉树的定义与构建四叉树的细化四叉树的传播 3.3. Mask Transfiner Architec…

修改Kali Linux的镜像网站

由于官方的镜像可能会出现连接不上的问题导致无法安装我们所需要的包&#xff0c;所以需要切换镜像站为国内的&#xff0c;以下是一些国内常用的Kali Linux镜像网站&#xff0c;它们提供了与Kali Linux官方网站相同的软件包和资源&#xff0c;但访问速度更快&#xff1a; 清华…

Feign:服务挂了也不会走fallback

Feign 本质上是一个 HTTP 客户端&#xff0c;用于简化微服务之间的 HTTP 通信。它允许开发者通过定义接口和注解来声明式地编写 HTTP 客户端&#xff0c;而无需手动编写 HTTP 请求和响应处理的代码。 今天在模拟微服务A feign调用微服务B的时候&#xff0c;把微服务B关了&#…