caioj 1715 表达式的转换

本文深入讲解了前缀、中缀及后缀表达式之间的转换方法,包括使用栈和邻接表进行编码的详细步骤,以及如何处理优先级和括号问题,适用于理解和实现表达式解析算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题是我出的,也是很坑的。
【题意】
用程序实现前缀表达式、中缀表达式、后缀表达式的相互转化。
用1、2、3分别表示前缀表达式、中缀表达式、后缀表达式。
输入表达式可能会出现一连串数字,但请把他们看成多个一位数,即123表示1 2 3,以降低大家编码的复杂程度。
输出表达式也不用在中间加空格。
数字均在1~9范围内,且运算符只有+ - * / ^ 5种。(^为幂运算符,幂运算的优先级高于加减乘除)
特殊的,输出的是中缀表达式时,中缀表达式不允许有多余的括号,只有必须时才能加括号,以保证输出的中缀
表达式的运算顺序与输入的前缀表达式或后缀表达式运算顺序相同。
问题只需4个操作:把中缀表达式转成前缀表达式、后缀表达式,把前缀表达式、后缀表达式转成中缀表达式。

1、2问题是类似的。

将中缀表达式转换为前缀表达式:
遵循以下步骤:
(1) 初始化两个栈:运算符栈ops和储存中间结果的栈p;
(2) 从右至左扫描中缀表达式;
(3) 遇到操作数时,将其压入p;
(4) 遇到运算符时,比较其与ops栈顶运算符的优先级,若ops栈顶符号的优先级高于当前符号的,就把它弹入p。
(5) 遇到括号时:
(5-1) 如果是右括号“)”,则直接压入ops;
(5-2) 如果是左括号“(”,则依次弹出ops栈顶的运算符,并压入p,直到遇到右括号为止,此时将这一对括号丢弃;
(6) 重复步骤(2)至(5),直到表达式的最左边;
(7) 将ops中剩余的运算符依次弹出并压入p;
(8) 依次弹出p中的元素并输出,结果即为中缀表达式对应的前缀表达式。
例如,将中缀表达式“1+((2+3)×4)-5”转换成前缀表达式"- + 1 × + 2 3 4 5"

将中缀表达式转换成后缀表达式,与上面类似。
不同之处:p为字符串数组;从左往右扫;遇到运算符时,比较其与ops栈顶运算符的优先级,若ops栈顶符号的优先级不低于当前符号的,就把它加入p;p为答案。

3、4问题是难点。为了优化,还需要写邻接表。

将前缀表达式转换成中缀表达式:
1.用一个栈in存中缀表达式。
2.从右往左扫描。
3.若当前元素为数字,则把它入栈。
4.若为运算符,则需注意优先级。
设运算符,栈顶两元素形如"op  A   B",则需要变成"A  op  B"。设运算符,栈顶两元素形如"op ~~A ~~~B",则需要变成"A~~op~~ B"。"op  A   B","A  op  B"
设A、B最后的操作的运算符分别a,b,grade(op)为返回优先级的函数(大的先操作)设A、B最后的操作的运算符分别a,b,grade(op)为返回优先级的函数(大的先操作)ABa,b,grade(op)()
则当grade(a)&lt;grade(op)时,A需要加括号。则当grade(a)&lt;grade(op)时,A需要加括号。grade(a)<grade(op)A
当grade(op)≤grade(b)时,B需要加括号。当grade(op)\le grade(b)时,B需要加括号。grade(op)grade(b)B
5.重复3-4,直到扫完。

将后缀表达式转换成中缀表达式,除了从左往右扫描,大体上没有与上面的不同之处。

代码:

STL版

//前缀、中缀、后缀表达式之间的转换。 
//这是一道数据结构题,考察邻接表和栈。 
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=40010;

int grade(char op)//优先级。用于中缀转前后缀 
{
	switch(op){
		case '+':
		case '-':
			return 1;
		case '*':
		case '/':
			return 2;
		case '^':
			return 3;
		case 0:
			return 4;
		}
	return 0;
}

void to_postfix(char s[])
{
	stack<char>ops;//符号和后缀表达式 
	vector<char>p;
	int n=strlen(s);
	for(int i=0;i<n;i++)
	{
		char c=s[i];
		if('0'<=c&&c<='9')p.push_back(c);
		else
		{
			if(c=='(')ops.push(c);
			else if(c==')')
			{
				while(ops.size()&&(c=ops.top())!='(')
				{
					p.push_back(c);
					ops.pop();
				}
				ops.pop();
			}
			else
			{
				while(ops.size()&&grade(ops.top())>=grade(c))
				{
					p.push_back(ops.top());
					ops.pop();
				}
				ops.push(c);
			}
		}
	}
	while(ops.size())p.push_back(ops.top()),ops.pop();
	n=0;
	for(vector<char>::iterator i=p.begin();i<p.end();i++)
		s[n++]=*i;
	s[n]=0;
}

void to_prefix(char s[])
{
	stack<char>ops,p;
	int n=strlen(s);
	for(int i=n-1;i>=0;i--)
	{
		char c=s[i];
		if('0'<=c&&c<='9')p.push(c);
		else 
		{
			if(c==')')ops.push(c);
			else if(c=='(')
			{
				while(ops.size()&&(c=ops.top())!=')')
				{
					p.push(c);
					ops.pop();
				}
				ops.pop();
			}
			else
			{
				while(ops.size()&&grade(ops.top())>grade(c))
				{
					p.push(ops.top());
					ops.pop();
				}
				ops.push(c);
			}
		}
	}
	while(ops.size())p.push(ops.top()),ops.pop(); 
	n=0;
	while(p.size())
		s[n++]=p.top(),p.pop();
	s[n]=0;
}

struct node//单个字符的存储。目标——用邻接表存字符串。 
{
	char c;
	int r;
	node(){r=0;}
}a[N];int tot;

struct segment
{
	int l,r;//左右指针。
	char op;//最后一个操作符。
	segment(){op=0;}
};

void add(segment &x)//加括号。
{
	 a[++tot].c='(';
	 a[tot].r=x.l;
	 x.l=tot;
	 a[++tot].c=')';
	 a[x.r].r=tot;
	 x.r=tot;
}

void con(segment &x,char op,segment y)//connect
{
	a[++tot].c=op;
	a[x.r].r=tot;
	a[tot].r=y.l;
	x.r=y.r;
	x.op=op;
}

void from_postfix(char s[])
{
	stack<segment>in;//infix
	tot=0;
	int n=strlen(s);
	for(int i=0;i<n;i++)
	{
		char c=s[i];
		if('0'<=c&&c<='9')
		{
			a[++tot].c=c;
			segment now;
			now.l=now.r=tot;
			in.push(now);
		}
		else
		{
			segment b=in.top();in.pop();
			segment a=in.top();in.pop();
			int l,r,m=grade(c);
			r=grade(b.op);
			l=grade(a.op);
			
			if(l<m)add(a);
			if(m>=r)add(b);
			con(a,c,b);
			in.push(a);
		}
	}
	n=0;
	for(int i=in.top().l;	i ;i=a[i].r)
		s[n++]=a[i].c;
	s[n]=0;
}

void from_prefix(char s[])
{
	stack<segment>in;//infix
	tot=0;
	int n=strlen(s);
	for(int i=n-1;i>=0;i--)
	{
		char c=s[i];
		if('0'<=c&&c<='9')
		{
			a[++tot].c=c;
			segment now;
			now.l=now.r=tot;
			in.push(now);
		}
		else
		{
			segment a=in.top();in.pop();
			segment b=in.top();in.pop();
			int l,r,m=grade(c);
			l=grade(a.op);
			r=grade(b.op);
			
			if(l<m)add(a);
			if(m>=r)add(b);
			con(a,c,b);
			in.push(a);
		}
	}
	n=0;
	for(int i=in.top().l;	i ;i=a[i].r)
		s[n++]=a[i].c;
	s[n]=0;
}

char s[N];
int main()
{
	int a,b;scanf("%d%d",&a,&b);
	scanf("%s",s);
	
	if(a==1)from_prefix(s);
	else if(a==3)from_postfix(s);
	
	if(b==1)to_prefix(s);
	else if(b==3)to_postfix(s);
	
	printf("%s",s);
	return 0;
}

朴素版

//前缀、中缀、后缀表达式之间的转换。 
//这是一道数据结构题,考察邻接表和栈。 #include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+100;

int grade(char op)//优先级。用于中缀转前后缀 
{
	switch(op){
		case '+':
		case '-':
			return 1;
		case '*':
		case '/':
			return 2;
		case '^':
			return 3;
		case 0:
			return 4;
		}
	return 0;
}

void to_postfix(char s[])
{
	char ops[N],p[N];int opl=0,pl=0;//符号和后缀表达式 
	memset(p,0,sizeof(p)); 
	int n=strlen(s);
	for(int i=0;i<n;i++)
	{
		char c=s[i];
		if('0'<=c&&c<='9')p[++pl]=c;
		else
		{
			if(c=='(')ops[++opl]=c;
			else if(c==')')
			{
				while(opl>0&&ops[opl]!='(')
				{
					p[++pl]=ops[opl--];
				}
				--opl;
			}
			else
			{
				while(opl>0&&grade(ops[opl])>=grade(c))
				{
					p[++pl]=ops[opl--];
				}
				ops[++opl]=c;
			}
		}
	}
	while(opl>0)p[++pl]=ops[opl--];
	p[++pl]=0;
	for(int i=0;i<pl;i++)s[i]=p[i+1]; 
}

void to_prefix(char s[])
{
	char ops[N],p[N];int opl=0,pl=0;//符号栈和前缀表达式 
	memset(p,0,sizeof(p)); 
	int n=strlen(s);
	for(int i=n-1;i>=0;i--)
	{
		char c=s[i];
		if('0'<=c&&c<='9')p[++pl]=c;
		else
		{
			if(c==')')ops[++opl]=c;
			else if(c=='(')
			{
				while(opl&&ops[opl]!=')')
				{
					p[++pl]=ops[opl--];
				}
				--opl;
			}
			else
			{
				while(opl&&grade(ops[opl])>grade(c))
				{
					p[++pl]=ops[opl--];
				}
				ops[++opl]=c;
			}
		}
	}
	while(opl>0)p[++pl]=ops[opl--];
	for(int i=0,j=pl;i<pl;i++,j--)s[i]=p[j]; 
	s[pl]=0;
}

struct node//单个字符的存储。目标——用邻接表存字符串。
{
	char c;
	int r;
	node(){r=0;}
}a[N];int tot;

struct segment
{
	int l,r;//左右指针。
	char op;//最后一个操作符。
	segment(){op=0;}
};

void add(segment &x)//加括号。
{
	 a[++tot].c='(';
	 a[tot].r=x.l;
	 x.l=tot;
	 a[++tot].c=')';
	 a[tot].r=0;
	 a[x.r].r=tot;
	 x.r=tot;
}

void con(segment &x,char op,segment y)//connect
{
	a[++tot].c=op;
	a[x.r].r=tot;
	a[tot].r=y.l;
	x.r=y.r;
	x.op=op;
}

void from_postfix(char s[])
{
	segment in[N>>1];int top=0;//infix
	tot=0;
	int n=strlen(s);
	for(int i=0;i<n;i++)
	{
		char c=s[i];
		if('0'<=c&&c<='9')
		{
			a[++tot].c=c;
			top++;
			in[top].l=in[top].r=tot;
			in[top].op=0;
		}
		else
		{
			segment b=in[top--];
			segment &a=in[top];
			int l,r,m=grade(c);
			r=grade(b.op);
			l=grade(a.op);
			
			if(l<m)add(a);
			if(m>=r)add(b);
			con(a,c,b);
		}
	}
	memset(s,0,N);
	int i,j;
	for(i=in[top].l,j=0;i ;i=a[i].r,j++)s[j]=a[i].c;
}

void from_prefix(char s[])
{
	segment in[N>>1];int top=0;//infix
	tot=0;
	int n=strlen(s);
	for(int i=n-1;i>=0;i--)
	{
		char c=s[i];
		if('0'<=c&&c<='9')
		{
			a[++tot].c=c;
			++top;
			in[top].l=in[top].r=tot;
			in[top].op=0;
		}
		else
		{
			segment a=in[top--];
			segment b=in[top];
			int l,r,m=grade(c);
			r=grade(b.op);
			l=grade(a.op);
			
			if(l<m)add(a);
			if(m>=r)add(b);
			con(a,c,b);
			in[top]=a;
		}
	}
	memset(s,0,N);
	int i,j;
	for(i=in[top].l,j=0;i ;i=a[i].r,j++)
		s[j]=a[i].c;
}

char s[N];
int main()
{
	int a,b;scanf("%d%d",&a,&b);
	scanf("%s",s);
	
	if(a==1)from_prefix(s);
	else if(a==3)from_postfix(s);
	
	if(b==1)to_prefix(s);
	else if(b==3)to_postfix(s);
	
	printf("%s",s);
	return 0;
}
内容概要:本文介绍了基于Python实现的SSA-GRU(麻雀搜索算法优化门控循环单元)时间序列预测项目。项目旨在通过结合SSA的全局搜索能力和GRU的时序信息处理能力,提升时间序列预测的精度和效率。文中详细描述了项目的背景、目标、挑战及解决方案,涵盖了从数据预处理到模型训练、优化及评估的全流程。SSA用于优化GRU的超参数,如隐藏层单元数、学习率等,以解决传统方法难以捕捉复杂非线性关系的问题。项目还提供了具体的代码示例,包括GRU模型的定义、训练和验证过程,以及SSA的种群初始化、迭代更新策略和适应度评估函数。; 适合人群:具备一定编程基础,特别是对时间序列预测和深度学习有一定了解的研究人员和技术开发者。; 使用场景及目标:①提高时间序列预测的精度和效率,适用于金融市场分析、气象预报、工业设备故障诊断等领域;②解决传统方法难以捕捉复杂非线性关系的问题;③通过自动化参数优化,减少人工干预,提升模型开发效率;④增强模型在不同数据集和未知环境中的泛化能力。; 阅读建议:由于项目涉及深度学习和智能优化算法的结合,建议读者在阅读过程中结合代码示例进行实践,理解SSA和GRU的工作原理及其在时间序列预测中的具体应用。同时,关注数据预处理、模型训练和优化的每个步骤,以确保对整个流程有全面的理解。
内容概要:本文详细介绍了如何使用PyQt5创建一个功能全面的桌面备忘录应用程序,涵盖从环境准备、数据库设计、界面设计到主程序结构及高级功能实现的全过程。首先,介绍了所需安装的Python库,包括PyQt5、sqlite3等。接着,详细描述了SQLite数据库的设计,创建任务表和类别表,并插入默认类别。然后,使用Qt Designer设计UI界面,包括主窗口、任务列表、工具栏、过滤器和日历控件等。主程序结构部分,展示了如何初始化UI、加载数据库数据、显示任务列表以及连接信号与槽。任务管理功能方面,实现了添加、编辑、删除、标记完成等操作。高级功能包括类别管理、数据导入导出、优先级视觉标识、到期日提醒、状态管理和智能筛选等。最后,提供了应用启动与主函数的代码,并展望了扩展方向,如多用户支持、云同步、提醒通知等。 适合人群:零基础或初学者,对Python和桌面应用程序开发感兴趣的开发者。 使用场景及目标:①学习PyQt5的基本使用方法,包括界面设计、信号与槽机制;②掌握SQLite数据库的基本操作,如创建表、插入数据、查询等;③实现一个完整的桌面应用程序,具备增删改查和数据持久化功能;④了解如何为应用程序添加高级特性,如类别管理、数据导入导出、到期日提醒等。 阅读建议:此资源不仅适用于零基础的学习者,也适合有一定编程经验的开发者深入理解PyQt5的应用开发。建议读者跟随教程逐步实践,结合实际操作来理解和掌握每个步骤,同时可以尝试实现扩展功能,进一步提升自己的开发技能。
本次的学生体质健康信息管理网站,按照用户的角色可以分为教师与学生,后台设置管理员角色来对学生的信息进行管理。,设计如下: 1、后台管理系统 后台管理系统主要是为该系统的管理员提供信息管理服务的系统,具体包括的功能模块如下: (1)管理员信息管理 (2)教师信息管理 (3)学生信息管理 (4)健康信息统计(图形化进行健康,亚健康等学生的信息数量统计) 2、教师角色的功能模块设计 教师角色所需要的功能模块主要包括了如下的一些内容: (1)个人资料修改 (2)学生体质健康管理:录入相关数据,包括但不限于身高、体重、肺活量、视力等生理指标以及运动能力、身体成分、骨密度等健康指标,并且设置健康,亚健康状态 (3)学生健康建议:根据体质信息,进行学生健康的建议 (4)健康预警:对健康出问题的学生,进行健康预警 (5)饮食和锻炼情况管理,查看 3、学生角色 学生角色可以通过该信息网站看到个人的基本信息,能够看到教师给与学生的健康建议等,功能模块设计如下: (1)个人资料修改 (2)我的健康建议查看 (3)我的健康预警 (4)饮食和锻炼情况管理,记录平时的饮食和锻炼情况 完整前后端源码,部署后可正常运行! 环境说明 开发语言:Java后端 框架:ssm,mybatis JDK版本:JDK1.8+ 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:eclipse/idea Maven包:Maven3.3+ 部署容器:tomcat7.5+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Infinite_Jerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值