Luogu P1175 表达式的转换 题解

没看题解手打蓝题,写篇题解庆祝。

题目大意

给出一个中缀表达式,输出后缀表达式并依次输出求解步骤。

具体思路

Step1:将中缀表达式转换成后缀表达式;

首先我们需要一个栈来作为转换的工具,并将算法最后得到的数字和字符分别存在两个数组中;

char a[105],chr[105];
stack <char> s;
int num[105],cnt;

其中a是输入的字符串,chr存运算符,num存数字cnt存储当前存的字符数字个数。

然后是基本的中缀转后缀的步骤;

⑴ 初始化两个栈:运算符栈s1和储存中间结果的栈s2;

⑵ 从左至右扫描中缀表达式;

⑶ 遇到操作数时,将其压s2;

⑷ 遇到运算符时,比较其与s1栈顶运算符的优先级:

① 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;

② 否则,若优先级比栈顶运算符的高,也将运算符压入s1;

③ 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到①与s1中新的栈顶运算符相比较;

⑸ 遇到括号时:

① 如果是左括号“(”,则直接压入s1;

② 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;

⑹ 重复步骤⑵至⑸,直到表达式的最右边;

⑺ 将s1中剩余的运算符依次弹出并压入s2;

⑻ 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

转换思路来自这里(实际打代码时未参考,这里纯粹是懒得打qwq)

有了思路,我们就会知道,首先我们需要一个给出运算符优先级的函数:

il int getPriority(char ch) {
	int level=0;
	switch(ch){
		case '(':
    		level=1;
    		break;
    	case '+':
    	case '-':
    		level=2;
    		break;
    	case '*':
    	case '/':
    		level=3;
    		break;
		case '^':
			level=4;
    	default:
    		break;
	}
	return level;
}

and根据思路模拟,注意其中的小细节:

for(int i=0;i<strlen(a);i++){
	if(a[i]>='0'&&a[i]<='9') num[cnt++]=(int)a[i]-'0';
	else{
		if(a[i]==')'){
			while(s.top()!='('){
				chr[cnt++]=s.top();
				s.pop();
			}
			s.pop();
		}
		else{
			if(s.empty()) s.push(a[i]);
			else{
				if(a[i]=='(') s.push(a[i]);
				else{
					while(!s.empty()&&getPriority(s.top())>=getPriority(a[i])){
						chr[cnt++]=s.top();
						s.pop();
					}
					s.push(a[i]);
				}
			}
		}
	}
}
while(!s.empty()){
	chr[cnt++]=s.top();
	s.pop();
}
print();

这样对中缀表达式的处理就完成了!

Step2:计算步骤;

这里我们要明白一点:每次计算会删去两个数字和一个运算符,并新增一个数字

所以说!我们每次操作后将cnt-2,就可以得到当前的算式长度了(真是个伟大的发现呢哈哈哈哈)!

然后就是每找到一个运算符,就对前面的两个数字进行操作,并对数字和运算符进行删减,当cnt=1,也就是算式中只剩下一个数字时,我们就得到了答案!

下面是这部分的具体代码,tot记录当前while循环里遍历到了第几位;实际上就是用俩数组模拟栈,注意细节就行了:

while(cnt!=1){
	tot++;
	if(chr[tot]==0) continue;
	else{
		switch(chr[tot]){
		case '+':
			num[tot-2]=num[tot-2]+num[tot-1];
			del(tot);
			break;
		case '-':
			num[tot-2]=num[tot-2]-num[tot-1];
			del(tot—);
			break;
		case '*':
			num[tot-2]=num[tot-2]*num[tot-1];
			del(tot);
			break;
		case '/':
			num[tot-2]=num[tot-2]/num[tot-1];
			del(tot);
			break;
		case '^':
			num[tot-2]=pow(num[tot-2],num[tot-1]);
			del(tot);
			break;
		default:
			break;
		}
		print();
		tot=0;
	}
}

以及其中的删除函数:

il void del(int to){
	for(int i=to;i<cnt;i++) num[i-1]=num[i+1];
	for(int i=to;i<cnt;i++) chr[i-1]=chr[i+1];
	cnt-=2;
}

Step3:输出

因为我们是一位一位存的所以说两个数组的同一位置上,有运算符就没数字,有数字就没运算符,遍历一遍依次输出就行:

il void print(){
	for(int i=0;i<cnt;i++){
		if(chr[i]!=0) printf("%c ",chr[i]);
		else printf("%d ",num[i]);
	}
	printf("\n");
}

到这就结束了,说实话这蓝题有一点水,个人觉得是黄题。
下面是AC代码:

//By Vanilla_RX
#include <bits/stdc++.h>
#define ll long long
#define ull unsinged long long
#define il inline
#define rg register
using namespace std;
il ll read(){
	ll X=0;bool flag=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') flag=0;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		X=(X<<1)+(X<<3)+ch-'0';
		ch=getchar();
	}
	if(flag) return X;
	return ~(X-1);
}
il void write(ll X){
	if(X<0){
		X=~(X-1);
		putchar('-');
	}
	if(X>9) write(X/10);
	putchar(X%10+'0');
}
char a[105],chr[105];
stack <char> s;
int num[105],cnt,tot;
il int getPriority(char ch) {
	int level=0;
	switch(ch){
		case '(':
    		level=1;
    		break;
    	case '+':
    	case '-':
    		level=2;
    		break;
    	case '*':
    	case '/':
    		level=3;
    		break;
		case '^':
			level=4;
    	default:
    		break;
	}
	return level;
}
il void print(){
	for(int i=0;i<cnt;i++){
		if(chr[i]!=0) printf("%c ",chr[i]);
		else printf("%d ",num[i]);
	}
	printf("\n");
}
il void del(int to){
	for(int i=to;i<cnt;i++) num[i-1]=num[i+1];
	for(int i=to;i<cnt;i++) chr[i-1]=chr[i+1];
	cnt-=2;
}
int main(){
	scanf("%s",&a);
	for(int i=0;i<strlen(a);i++){
		if(a[i]>='0'&&a[i]<='9') num[cnt++]=(int)a[i]-'0';
		else{
			if(a[i]==')'){
				while(s.top()!='('){
					chr[cnt++]=s.top();
					s.pop();
				}
				s.pop();
			}
			else{
				if(s.empty()) s.push(a[i]);
				else{
					if(a[i]=='(') s.push(a[i]);
					else{
						while(!s.empty()&&getPriority(s.top())>=getPriority(a[i])){
							chr[cnt++]=s.top();
							s.pop();
						}
						s.push(a[i]);
					}
				}
			}
		}
	}
	while(!s.empty()){
		chr[cnt++]=s.top();
		s.pop();
	}
	print();
	while(cnt!=1){
		tot++;
		if(chr[tot]==0) continue;
		else{
			switch(chr[tot]){
			case '+':
				num[tot-2]=num[tot-2]+num[tot-1];
				del(tot);
				break;
			case '-':
				num[tot-2]=num[tot-2]-num[tot-1];
				del(tot);
				break;
			case '*':
				num[tot-2]=num[tot-2]*num[tot-1];
				del(tot);
				break;
			case '/':
				num[tot-2]=num[tot-2]/num[tot-1];
				del(tot);
				break;
			case '^':
				num[tot-2]=pow(num[tot-2],num[tot-1]);
				del(tot);
				break;
			default:
				break;
			}
			print();
			tot=0;
		}
	}
	system("pause");
	return 0;
}

完~

posted @ 2021-05-06 21:15  Vanilla_RX  阅读(204)  评论(0)    收藏  举报