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;
}
完~

浙公网安备 33010602011771号