zoukankan      html  css  js  c++  java
  • 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.若为运算符,则需注意优先级。
    "op  A   B","A  op  B"设运算符,栈顶两元素形如"op ~~A ~~~B",则需要变成"A~~op~~ B"。
    ABa,b,grade(op)()设A、B最后的操作的运算符分别a,b,grade(op)为返回优先级的函数(大的先操作)
    grade(a)<grade(op)A则当grade(a)<grade(op)时,A需要加括号。
    grade(op)grade(b)B当grade(op)le 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;
    }
    
  • 相关阅读:
    git本地及远程分支回退
    Git怎样撤销一次分支的合并Merge
    git仓库迁移的两种解决方案
    【转】Linux下mysql操作
    Linux下tomcat相关操作
    Linux下top命令详解
    Linux下crontab详解
    Linux下mysql安装
    Linux下RPM包管理
    Linux下用户组、文件权限详解
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373908.html
Copyright © 2011-2022 走看看