NOIP2013普及组T2
只有加法和乘法的表达式
思考:
使用tok来存放操作数或操作符(在编译器词法分析中称之为token,故简写为tok);输入只有一行可以用fgets,不知道题目给的输入文件有没有换行(fgets是会读入换行符的),所以还要加个判断,不然存放的时候会把换行符也当做运算符
对于2+3+...的表达式,读到2+3之后可以直接先算出5,结果是与5+...等价的;然而读到2+3...的表达式,需要先计算3...后面的内容,因为乘法的优先级比加法要高;故只读到2+3的时候不能先做计算,反之读到2*3可以先算。
每次读到操作数肯定要进栈;读到操作符,则根据优先级进行判断和计算;因此需要两个栈
一个简单的便于理解的小图示
大致推断出过程:
解析token
若为操作数则入栈
若为运算符:
若运算符栈为空,则将当前运算符入栈
若当前运算符优先级高于栈顶运算符,则将当前运算符入栈
否则不断循环,直至运算符栈为空或者当前运算符优先级高于栈顶运算符:
栈顶两个操作数出栈
栈顶运算符出栈
将两个操作数进行计算,再进栈
循环结束,将当前运算符入栈
实际写代码时考虑到判断运算符栈为空比较困难,需要一个哨兵;
大致长这样,关于括号的事情后面再写
#include<bits/stdc++.h>
using namespace std;
char tok[100000][20];
int tok_max=0;
char s[500000];int calc(char op,int num1,int num2){assert(op=='+'||op=='*');if(op=='+')return num1+num2;if(op=='*')return num1*num2;
}int priority(char op){if(op=='*')return 2;if(op=='+')return 1;
}
int main(){fgets(s,sizeof(s),stdin);int num=0;if(s[strlen(s)-1]=='\n'){s[strlen(s)-1]=0;}for(int i=0;i<strlen(s);i++){if(isdigit(s[i])){num=num*10+s[i]-'0';}else{++tok_max;++tok_max;sprintf(tok[tok_max-1],"%d",num);*tok[tok_max]=s[i];num=0;}}++tok_max;sprintf(tok[tok_max],"%d",num);//printf("tok_max..%d\n",tok_max);//for(int i=1;i<=tok_max;i++){// puts(tok[i]);//}stack<int>optr,opnd;//运算符栈、操作数栈optr.push('#');//检验运算符栈非空的哨兵 for(int i=1;i<=tok_max;i++){if(isdigit(*tok[i])){int num1;sscanf(tok[i],"%d",&num1);opnd.push(num1);}else{for(;optr.top()!='#' && priority(*tok[i]) <= priority(optr.top());){int num2=opnd.top();opnd.pop();int num3=opnd.top();opnd.pop();char op=optr.top();optr.pop();opnd.push(calc(op,num3,num2)%10000);}optr.push(*tok[i]);}}//printf("%d\n",opnd.top());for(;optr.top()!='#';){int num2=opnd.top();opnd.pop();int num3=opnd.top();opnd.pop();char op=optr.top();optr.pop();opnd.push(calc(op,num3,num2)%10000);}printf("%d\n",opnd.top()%10000);return 0;
}