题目链接:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19367
题意:
给定一个计算式,计算式合法。每个运算符和数字之间差一个空格,输出其值。
思路:
逆波兰式模板题。
逆波兰式主要是这样一个操作。两个栈(最初和队列弄混。队列为先进先出),一个栈s1存储逆波兰式,一个栈s2作临时存储,存储操作数。读入数字时,直接存入s1.如果题目说明数字的长度会大于一,则在遇到遍历字符串遇到非数字字符后,向s1里压入一个” ”(空串)代表分割。
关键来了,操作的优先级p1,栈顶的优先级p2。若p1小于等于p2,则把p2的栈顶元素弹出并压入s1,知道p1大于p2,然后把p1压入s2。注意是“小于等于”。
输出计算的时候,遇到操作M,栈顶第一个操作数X1,第二个X2,则根据栈的结构特点,结果应为X2 (M)X1
扩展式的想一想,如果存在左括号(、右括号)等蛋疼的符号。遇到右括号则弹栈直到遇到左括号,同时改变里面的操作数。
源码:
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <iostream>
using namespace std;
int const MAXN = 2000;
char s0[MAXN],porlan[MAXN];
int priority(char c)
{
switch(c){
case '#':return 0;
case '+':return 1;
case '-':return 2;
case '*':return 3;
case '/':return 4;
}
}
void trans(char a[],char b[])
{
int len = strlen(a);
stack<char>ss;
while(!ss.empty())
ss.pop();
int tot = 0;
for(int i=0; i<len; i++){
if(isdigit(a[i]) || a[i]==' ')
b[tot++] = a[i];
else{
if(priority(a[i])<=2 ){
while(!ss.empty()){
b[tot++] = ss.top();
ss.pop();
}
}
else{
while(!ss.empty() && priority(ss.top())>2 ){
b[tot++] = ss.top();
ss.pop();
}
}
ss.push(a[i]);
}
}
while(!ss.empty()){
if(ss.top() == '#')
break;
b[tot++] = ' ';
b[tot++] = ss.top();
ss.pop();
}
b[tot] = '\0';
}
double cal(char a[])
{
stack<double>ss;
while(!ss.empty())
ss.pop();
double temp = 0;
int tot = 0;
double t1,t2;
for(int i=0; i<strlen(a); i++){
if(a[i]>='0' && a[i]<='9'){
temp = temp*10 + a[i] - '0';
}
else if(a[i] == ' '){
if(isdigit(a[i-1]) || temp){
ss.push(temp);
temp = 0;
}
}
else{
t2 = ss.top();ss.pop();
t1 = ss.top();ss.pop();
switch(a[i]){
case '+':
t1 = t1 + t2;break;
case '-':
t1 = t1 - t2;break;
case '*':
t1 = t1 * t2;break;
case '/':
t1 = t1 / t2;break;
}
// printf("t1 = %.2f\n",t1);
ss.push(t1);
}
}
return ss.top();
}
int main()
{
while(gets(s0)){
if(!strcmp(s0,"0"))
break;
trans(s0,porlan);
double ans = cal(porlan);
printf("%.2f\n",ans);
}
return 0;
}