版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Xiblade/article/details/82936868
编写机试C++代码时,要注意封装的粒度。何种粒度的操作应该封装入函数中,何种粒度应该暴露在外面形成流畅的逻辑。本文非常注意这一点,在main函数中的操作都是重复和类似的,而将更加细粒度的操作封装入函数中。
#include<cstdio>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<map>
using namespace std;
struct Node{
double num;
char op;
bool isNum; // true : 数字 false :运算符
};
// 去掉整个字符串所有空格的函数
void wipeSpace(string &fmla){
for(string::iterator it = fmla.end(); it != fmla.begin(); it--){ // 需要反向遍历,正向遍历时会跳着走
if(*it == ' ') fmla.erase(it);
}
}
// 在中缀式字符串中得到一个单元的函数
// 处理后中缀式字符串会相应地减少
Node secureNode(string &fmla){
Node rt;
if((*fmla.begin() >= '0' && *fmla.begin() <= '9') || *fmla.begin() == '.' ){ // 数字或者小数点
string tmp;
while((*fmla.begin() >= '0' && *fmla.begin() <= '9') || *fmla.begin() == '.'){
tmp += *fmla.begin();
fmla.erase(fmla.begin(), fmla.begin() + 1);
}
sscanf(tmp.c_str(), "%lf", &rt.num);
rt.isNum = true;
} else{
rt.op = *fmla.begin();
fmla.erase(fmla.begin(), fmla.begin() + 1);
rt.isNum = false;
}
return rt;
}
//初始化用于比较优先级的map
void initSequence(map<char, int> &sequence){
sequence['+'] = 1;
sequence['-'] = 1;
sequence['*'] = 2;
sequence['/'] = 2;
}
// 比较优先级的函数
bool compareSeq(Node opNodeA, Node opNodeB, map<char, int> sequence){
bool aBigThanB = false;
if(sequence[opNodeA.op] > sequence[opNodeB.op]) return true;
else return false;
}
// 根据字符进行运算的函数
Node calc(double num1, double num2, char op){
Node rt;
switch(op){
case '+':
rt.num = num1 + num2;
break;
case '-':
rt.num = num1 - num2;
break;
case '*':
rt.num = num1 * num2;
break;
case '/':
rt.num = num1 / num2;
break;
}
rt.isNum = true;
//printf("%.2f %c %.2f = %.2f\n", num1, op, num2, rt.num); 这里print可以得到运算过程
return rt;
}
string fmla; // 存放算式
stack<Node> opSt; // 符号栈
queue<Node> fmQu; // 后缀式队列
map<char, int> sequence;
int main(){
initSequence(sequence);
while(getline(cin, fmla)){
if(fmla == "0"){
break;
}
// 去空格
wipeSpace(fmla);
// 解析后缀表达式
while(fmla.size() > 0){
Node n = secureNode(fmla);
if(n.isNum){
fmQu.push(n);
} else{
if(opSt.empty()) opSt.push(n);
else{
bool bigThanTop;
do{
// 循环比较操作符栈的优先级
bigThanTop = compareSeq(n, opSt.top(), sequence);
if(!bigThanTop){ // 如果优先级低于或等于 则符号栈弹入队列
fmQu.push(opSt.top());
opSt.pop();
}
}while(!bigThanTop && !opSt.empty());// 没碰到优先级比当前低的就一直弹
opSt.push(n);// 最终把当前符号压栈
}
}
}
while(!opSt.empty()){ // 符号栈中剩余的元素弹入队列
fmQu.push(opSt.top());
opSt.pop();
}
// 测试 打印优先级
// while(!fmQu.empty()){
// if(fmQu.front().isNum){
// printf("%.2f ", fmQu.front().num); // 注意! 打印格式不对,打出来的全是0
// } else{
// printf("%c ", fmQu.front().op);
// }
// fmQu.pop();
// }
// 计算后缀表达式
stack<Node> numSt;
while(!fmQu.empty()){
// 如果是数字,出队压栈
if(fmQu.front().isNum){
numSt.push(fmQu.front());
fmQu.pop();
} else{// 如果是运算符 则从数字栈中弹两个出来运算
Node num1 = numSt.top();
numSt.pop();
Node num2 = numSt.top();
numSt.pop();
Node op = fmQu.front();
fmQu.pop();
numSt.push(calc(num2.num, num1.num, op.op));
// 栈中两个数 是反着的
}
}
// 50%错误并不是整数和浮点数输出区别的问题
// double verify = (int)(numSt.top().num * 100)% 100;
// if(verify > 0)
printf("%.2f\n", numSt.top().num); // 输出要加回车换行 否则50%错误!!!
// else
// printf("%.0f", numSt.top().num);
}
return 0;
}