【机试练习】【C++】【codeup 1918】简单计算器

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/Xiblade/article/details/82936868
今日推荐