caioj 1715 表达式的转换

这道题是我出的,也是很坑的。
【题意】
用程序实现前缀表达式、中缀表达式、后缀表达式的相互转化。
用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.若为运算符,则需注意优先级。
设 运 算 符 , 栈 顶 两 元 素 形 如 " o p    A     B " , 则 需 要 变 成 " A    o p    B " 。 设运算符,栈顶两元素形如"op ~~A ~~~B",则需要变成"A~~op~~ B"。 "op  A   B","A  op  B"
设 A 、 B 最 后 的 操 作 的 运 算 符 分 别 a , b , g r a d e ( o p ) 为 返 回 优 先 级 的 函 数 ( 大 的 先 操 作 ) 设A、B最后的操作的运算符分别a,b,grade(op)为返回优先级的函数(大的先操作) ABa,b,grade(op)()
则 当 g r a d e ( a ) &lt; g r a d e ( o p ) 时 , A 需 要 加 括 号 。 则当grade(a)&lt;grade(op)时,A需要加括号。 grade(a)<grade(op)A
当 g r a d e ( o p ) ≤ g r a d e ( 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值