表达式的转换

news2024/11/18 21:17:45

题目:

表达式的转换 - 洛谷 P1175 - Virtual Judge

思路:

这道题可以拆成两问:

第一问,将中缀表达式转成后缀表达式放入一个数组

第二问,将后缀表达式的数组计算,并输出过程

第一问思路:

通过栈 + 递归的思路来解决,遍历中缀表达式,如果是数字则直接加入后缀表达式的数组。

如果是操作符要分如下三种情况:

1.栈为空,直接将操作符入栈。

2.栈不为空,该操作符比栈顶操作符优先级高,直接入栈。

3.栈不为空,该操作符比栈顶操作符优先级低或者相等,出栈顶操作符,加入后缀表达式的数组,并继续与下一个栈顶操作符判断。(两个^比较时,后来的^优先级更高,这是本题的特例)

 重点:

遇到括号时:

遇到左括号,开始递归,创建新的栈,先将括号里的转成后缀表达式。

遇到右括号,递归结束,讲栈中元素全部加入后缀表达式的数组。(详细看代码中的注释)

第二问思路:

现在我们已经拿到了一个后缀表达式,并存在数组里。

后缀表达式的计算,遍历后缀表达式数组,遇到数字将其入栈,遇到操作符,出两次栈顶元素并将结果入栈。

由于我们要打印过程,但STL中的stack并不支持随机访问,我们可以用vector来模拟栈的使用,没计算一次打印 vector中的元素 + 后缀表达式数组中剩下的元素。

详细讲解在代码中,步骤都有注释。

AC代码:

#include<iostream>
#include<stdio.h>
#include<string>
#include<stack>
#include<vector>
#include<math.h>
using namespace std;
vector<char> ret;//ret数组用于存放后缀表达式
char str[1000001];//str数组存放输入的中缀表达式
char* p = str;//通过p指针来遍历
//compare函数用于比较操作符的优先级
int compare(char a, char b)
{
	if (a == '+' || a == '-')
	{
		if (b == '*' || b == '/' || b == '^') return -1;
		else return 0;
	}
	else if (b == '+' || b == '-')
	{
		if (a == '*' || a == '/' || a == '^') return 1;
		else return 0;
	}
	else if (a == '*' || a == '/')
	{
		if (b == '^') return -1;
		else return 0;
	}
	else if (b == '*' || b == '/')
	{
		if (a == '^') return 1;
		else return 0;
	}
	//根据题意,两个^在一起时,应该判定后面来的^优先级更高
	else if (a == '^' && b == '^')
	{
		return 1;
	}
	else return 0;
}
//suffix函数作用 从p1指向的位置开始进行转后缀操作
void suffix(char* p1)
{
	//这里对全局变量p赋值是为了防止有递归结束,回溯后p指针回到进入递归的位置,我们要求p一直走不会因为递归结束后回来
	p = p1;
	//每次递归都要有新的栈,所以栈在函数体里创建
	stack<char> st;
	while(*p)
	{
		//如果遇到左括号,开始从这个括号右边的一个位置开始递归
		if (*p == '(')
		{
			p++;
			suffix(p);
			//递归完如果已经走到str结尾就直接break,防止出现RE
			if (*p == '\0')break;
		}
		//遇到右括号递归结束
		else if (*p == ')') 
		{
			//递归结束前全部操作符出栈,加入ret数组
			while (!st.empty())
			{
				char t = st.top();
				ret.push_back(t);
				ret.push_back(' ');
				st.pop();
			}
			//把p调整到右括号的右边一个位置,方便后续操作
			p++;
			return;
		}
		if (*p >= '0' && *p <= '9')//数字直接存入答案数组
		{
			ret.push_back(*p);
			ret.push_back(' ');
		}
		else//操作符入栈
		{
			char t;
			if (!st.empty()) t = st.top();
			while(1)
			{
				//当前操作符优先级比栈顶大,入栈
				if (st.empty()||compare(*p, t) > 0)
				{
					st.push(*p);
					t = st.top();
					break;
				}
				//比栈顶低或者等于,出栈顶操作符,加入答案数组
				else if (compare(*p, t) <= 0)
				{
					ret.push_back(t);
					ret.push_back(' ');
					st.pop();
					if (!st.empty()) t = st.top();
				}
			}
		}
		p++;
	}
	//遍历str结束。如果栈中还有元素,则全部出栈
	while (!st.empty())
	{
		ret.push_back(st.top());
		ret.push_back(' ');
		st.pop();
	}
}
//work函数用于最后计算过程的打印
void work()
{
	//因为要遍历打印,所以后缀表达式计算式的栈没有用stack,而是用vector,
	//因为stack无法遍历,而vector可以遍历且可以当栈使用
	vector<int> st1;
	int i = 0;
	for (i = 0;i < ret.size();i++)
	{
		//数字直接入栈
		if (ret[i] >= '0' && ret[i] <= '9')
		{
			st1.push_back(ret[i] - '0');
		}
		//空格不管直接跳过
		else if (ret[i] == ' ')
		{
			continue;
		}
		//剩下的都是操作符
		//操作符出现,开始出两个栈中元素进行计算
		else
		{
			int right = st1.back();//右操作数
			st1.pop_back();
			int left = st1.back();//左操作数
			st1.pop_back();
			//进行计算,并将结果入栈
			if (ret[i] == '+') st1.push_back(left + right);
			else if (ret[i] == '^') st1.push_back(pow(left,right));
			else if (ret[i] == '-') st1.push_back(left - right);
			else if (ret[i] == '*') st1.push_back(left * right);
			else if (ret[i] == '/') st1.push_back(left / right);
			//每进行一次计算,打印一次过程
			//第一个for打印栈中元素
			for (int j = 0;j < st1.size();j++)cout << st1[j]<<' ';
			//第二个for打印没在栈中的ret数组中的元素
			for (int j = i+2;j < ret.size() - 1;j++)cout << ret[j];
			//如果是最后一步则不用打印换行
			if (i == ret.size() - 2)continue;
			cout << endl;
		}
	}
}
int main()
{
	scanf("%s",str);
	suffix(p); 
	//此时得到后缀表达式全在ret数组里
	//根据题意先把ret打印一遍
	for (int i = 0;i < ret.size() - 1;i++)
	{
		cout << ret[i];
	}
	cout << endl;
	//work函数打印后续计算过程
	work();
	return 0;
}

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

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

相关文章

Python高维度大型气象矩阵存储策略分享

零、前情提要 最近需要分析全球范围多变量的数值预报数据&#xff0c;将grb格式的数据下载下来经过一通处理后需要将预处理数据先保存一遍&#xff0c;方便后续操作&#xff0c;处理完发现此时的数据维度很多&#xff0c;数据量巨大&#xff0c;使用不同的保存策略的解析难度和…

信息安全技术解析

在信息爆炸的今天&#xff0c;信息技术安全已成为社会发展的重要基石。随着网络攻击的日益复杂和隐蔽&#xff0c;保障数据安全、提升防御能力成为信息技术安全领域的核心任务。本文将从加密解密技术、安全行为分析技术和网络安全态势感知技术三个方面进行深入探讨&#xff0c;…

C++笔试强训9

文章目录 一、选择题1-5题6-10题 二、编程题题目一题目二 一、选择题 1-5题 函数形参是个int类型的引用&#xff0c;传参的时候直接传一个int类型的变量就行 故选A 1.malloc/calloc/realloc—>free 2. new / delete 3. new[] / delete[] 一定要匹配起来使用&#xff0c;否则…

猫头虎分享:Numpy知识点一文带你详细学习np.random.randn()

&#x1f42f; 猫头虎分享&#xff1a;Numpy知识点一文带你详细学习np.random.randn() 摘要 Numpy 是数据科学和机器学习领域中不可或缺的工具。在本篇文章中&#xff0c;我们将深入探讨 np.random.randn()&#xff0c;一个用于生成标准正态分布的强大函数。通过详细的代码示…

ADS 使用教程(二十九)Understanding Bounding Area Layer for FEM

上一篇&#xff1a;ADS 使用教程&#xff08;二十八&#xff09;Working with FEM Mesh & Field Data in ADS 这一节&#xff0c;我们来一起了解一下有限元法&#xff08;FEM&#xff09;中的边界区域层&#xff08;Bounding Area Layer&#xff09;&#xff0c;这是定义仿…

python项目实例和源码权限管理系统

✌网站介绍&#xff1a;✌10年项目辅导经验、专注于计算机技术领域学生项目实战辅导。 ✌服务范围&#xff1a;Java(SpringBoo/SSM)、Python、PHP、Nodejs、爬虫、数据可视化、小程序、安卓app、大数据等设计与开发。 ✌服务内容&#xff1a;免费功能设计、免费提供开题答辩P…

浅谈HOST,DNS与CDN

首先这个是网络安全的基础&#xff0c;需得牢牢掌握。 1.什么是HOST HOSTS文件&#xff1a; 定义&#xff1a; HOSTS文件是一个操作系统级别的文本文件&#xff0c;通常位于操作系统的系统目录中&#xff08;如Windows系统下的C:\Windows\System32\drivers\etc\hosts&#xf…

黑马头条vue2.0项目实战(二)——登录注册功能的实现

1. 布局结构 目标 能实现登录页面的布局 能实现基本登录功能 能掌握 Vant 中 Toast 提示组件的使用 能理解 API 请求模块的封装 能理解发送验证码的实现思路 能理解 Vant Form 实现表单验证的使用 这里主要使用到三个 Vant 组件&#xff1a; NavBar 导航栏 Form 表单 F…

windows 安装 Linux 子系统 Ubuntu,并编译安装nginx

1. 安装Ubuntu 首先可以在 Microsoft Store 自行搜索安装 Ubuntu&#xff0c;个人建议安装 22 版本的即可。Ubuntu安装完成后&#xff0c;以管理员身份打开CMD&#xff0c;运行如下命令&#xff1a; wsl --install 此时打开Ubuntu已经可以正常使用了。 2. 安装C/C编译器 对于…

动态规划专题:线性dp、背包问题,区间

目录 方块与收纳盒 舔狗舔到最后一无所有 可爱の星空 数字三角形 花店橱窗 [NOI1998]免费馅饼 [NOIP2002]过河卒 [NOIP2008]传球游戏 「木」迷雾森林 [NOIP2004]合唱队形 [NOIP1999]拦截导弹 数学考试 小A买彩票 购物 牛牛的旅游纪念品 [NOIP2001]装箱问题 [N…

网络轮询器 NetPoller

网络轮询器 NetPoller 网络轮询器是 Go 语言运行时用来处理 I/O 操作的关键组件&#xff0c;它使用了操作系统提供的 I/O 多路复用机制增强程序的并发处理能力。网络轮询器不仅用于监控网络 I/O&#xff0c;还能用于监控文件的 I/O&#xff0c;它利用了操作系统提供的 I/O 多路…

How can I fix my Flask server‘s 405 error that includes OpenAi api?

题意&#xff1a;解决包含OpenAI API的Flask服务器中出现的405错误&#xff08;Method Not Allowed&#xff0c;即方法不允许&#xff09; 问题背景&#xff1a; Im trying to add an API to my webpage and have never used any Flask server before, I have never used Java…

MATLAB进阶:函数和方程

经过前几天的学习&#xff0c;matlab基础我们已经大致了解&#xff0c;现在我们继续学习matlab更进一步的应用。 常用函数 在求解有关多项式的计算时&#xff0c;我们无可避免的会遇到以下几个函数 ypolyval(p,x)&#xff1a;求得多项式p在x处的值y&#xff0c;x可以是一个或…

ComfyUI反推提示词节点报错:Load model failed

&#x1f3a0;报错现象 反推提示词的时候会提示报错&#xff1a; Error occurred when executing WD14Tagger|pysssss: [ONNXRuntimeError] : 3 : NO_SUCHFILE : Load model from F:\ComfyUI-aki\custom_nodes\ComfyUI-WD14-Tagger\models\wd-v1-4-convnext-tagger-v2.onnx fa…

创建mysql库,及webserver使用编译

首先安装mysql sudo apt update sudo apt install mysql-server sudo systemctl status mysql #检查mysql是否安装成功 sudo mysql #进入mysqlSHOW DATABASES; create database yourdb; #创建一个名为yourdb的数据库USE yourdb; #使用刚才创建好的数据库 CREATE TABLE …

Go语言----reflect.DeepEqual函数

在使用go语言进行编程的时候&#xff0c;我们通常会对模块进行测试&#xff0c;在测试的过程中&#xff0c;经常会使用reflect.DeepEqual函数&#xff0c;这个函数是在reflect包中&#xff0c;其提供了运行时反射机制的标准库。其中的reflect.DeepEqual()函数是用来比较两个值是…

【知识梳理】Shell的变量计算

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 Shell中有很多变量的计算&#xff0c;会用到多种运算符。例如这几种&#xff1a; 1. Shell中常见的算术运算符 运算符意义&…

springboot-定时任务源码分析

springboot-定时任务源码分析 前言我们都知道开启 springboot的定时任务需要先使用 EnableScheduling 注解&#xff0c;在可以开启&#xff0c;那么 EnableScheduling 就是定时任务的源头&#xff0c;所以先从 EnableScheduling 开始分析 EnableScheduling 这个注解核心就是…

基于cubeMX的STM32的定时器使用

1、设置cubeMX 这里使用STM32F103RCT6芯片&#xff0c;以定时器2为例&#xff0c;时钟源选择内部时钟 参数设置&#xff0c;预分频7200&#xff0c;定时器周期10000&#xff0c;则表示定时1秒钟 打开定时器2通用中断 其他设置不用修改。时钟页面配置如下 最后生成代码。 2、在…

05.java中常用的类

1.包装类 基本类型包装类booleanBooleancharCharacterbyteByteintIntegerlongLongfloatFloatdoubleDoubleshortShort 从byte开始的包装类都是继承的Number&#xff0c;然后Number继承的object 从byte上面的都是直接继承的oblect (1).装箱和拆箱 装箱&#xff1a;基本类型--…