题目描述
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入描述:
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
输出描述:
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
示例1
输入
1 + 2
4 + 2 * 5 - 7 / 11
0
输出
3.00
13.36
对于题目本身而言,学过数据结构的大体思路应该都能想到,但是具体实现会有各类问题,本题是我在复试过程中使用的《王道机试指南》一书中做到的,该题涉及到了所学到的栈以及优先级判别,字符串输入输出和相关处理等问题,涉及范围较广,个人认为自己实现还是难度挺大的,特将调试过程中的问题和注意点记下来,当作笔记,大神看到莫当真。
#include<iostream>
#include<cstdio>
#include<stack>
#include<cctype>
//isdigit()函数要用到
#include<string>
using namespace std;
int Priority(char c){ //优先级依次排序
if(c=='#')
return 0;
else if(c=='$')
return 1;
else if(c=='+'||c=='-')
return 2;
else if(c=='*'||c=='/')
return 3;
}
double GetNumber(string str,int &index){
//获得下个数字
double number = 0;
while(isdigit(str[index])){
//该函数在头文件cctype中,该函数能够用来检查字符是否为十进制数字自符
//本题为过滤到空格以及运算符
number = number*10+str[index]-'0';
index++;
}
return number; //返回的是对应的操作数
}
double Calculate(double x,double y,char op){
double result = 0;
if(op =='+')
result = x+y;
else if(op=='-')
result = x-y;
else if(op =='*')
result = x*y;
else if(op == '/')
result = x/y;
return result;
}
int main(){
string str;
while(getline(cin,str)){
if(str=="0")
break; //终止条件
int index = 0; //字符串下标
stack<char> oper; //运算符栈
stack<double>data; //运算数栈
str+='$'; //字符串尾部添加$
oper.push('#'); //运算符栈底添加#
while(index<str.size()){
if(str[index]==' ') index++; //略过空格
else if(isdigit(str[index]))
data.push(GetNumber(str,index)); //将对应的数字入栈
else {
//比较运算符栈的栈顶元素与当前字符串中操作符的优先级高低
if(Priority(oper.top())<Priority(str[index])){
//优先级不如当前操作符的优先级高,因此入栈,字符串指针index后移
oper.push(str[index]);
index++;
}
else{
//栈顶的操作符优先级更高,需要将放入运算数栈中的栈顶和次栈顶元素进行运算
double y = data.top();
data.pop(); //移除栈顶元素
double x=data.top();
data.pop(); //注意是x?y进行运算,注意前后顺序
data.push(Calculate(x,y,oper.top()));
//注意还要将运算符栈的栈顶元素移除
oper.pop();
}
}
}printf("%.2f\n",data.top()); //保留到后几位的方式要学会
}
return 0;
}
对于学习本题的一些总结:
1.对于栈的定义可以使用STL(标准数据库),简单明了,不需要将重心放在如何定义栈上
固定格式问 stack <数据类型> 栈名 (运算符名可以定为 oper,运算数名可以定为 data)
而相关的操作为 .push() 为入栈,.top()为取出栈顶元素,.pop()为移除栈顶元素 (注意这里的top操作之后常常跟着pop操作,下一次用来访问新栈顶元素)
2.对于优先级排序的Priority()函数可以适当移植到其他类似问题中,只要是涉及优先级或是表达式求值均可适当运用
3.对于将输入的字符串中的数字提取出来的GetNumber()函数是十分有效的,此函数可以用在类似与输入一个字符串提取所有数字等相关要求中,务必记住
4.此程序的作者运用两个例外的符号表示栈的结束(#) 和($)表示表达式的结束
下附该题目对应的牛客网OJ网址