王道机试指南NO.12栈的应用之简单计算器

版权声明:本博全为博主学习日常,均为原创,请勿转载 https://blog.csdn.net/weixin_44332298/article/details/88034505

时间限制:1s 内存限制:32MB

题目描述

读入一个只包含+,-,*,/的非负整数计算表达式,计算该表达式的值。

输入

测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔,没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。

输出

对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。

样例输入

1 + 2
4 + 2 * 5 - 7 / 11
0

样例输出

3.00
13.36

题目分析

(1)设立两个堆栈,一个用来保存运算符,另一个用来保存数字。
(2)在表达式首尾添加标记运算符,该运算符运算优先级最低。
(3)从左到右依次遍历字符串,若遍历到运算符,则将其与运算符栈顶元素进行比较,若运算符栈栈顶运算符优先级小于该运算符或者此时运算符栈为空,则将该运算符压入堆栈。遍历字符串中下一个元素。
(4)若运算符栈栈顶运算符优先级大于该运算符,则弹出该栈顶运算符,再从数字栈栈中依次弹出两个栈顶数字,完成弹出的运算符对应的运算得到 结果后,再将该结果压入数字栈,重复比较此时栈顶运算符与当前遍历到的运算符优先级,视其优先级大小重复步骤(3),(4)。
(5)若遍历到表达式中的数字,则直接压入数字栈。
(6)若运算符堆栈中仅存有两个运算符且栈顶元素为人为添加的标记运算符,那么表达式运算结束,此时数字堆栈中唯一的数字即为表达式的值。

代码

#include <iostream>
#include <stdio.h>
#include <stack>
using namespace std;

char str[220];
int mat[][5] = {
	1,0,0,0,0,
	1,0,0,0,0,
	1,0,0,0,0,
	1,1,1,0,0,
	1,1,1,0,0
}; /*优先级矩阵,若mat[i][j]==1,则表示i号运算符优先级大于j号运算符   
+为1号,-为2号,*为3号,/为4号,人为添加在表达式收尾的标记运算符为0号*/

stack<int> op; //运算符栈,保存运算符编号
stack<double> in; //数字栈,运算结果可能存在浮点数
void getOp(bool &reto, int &retn, int &i){
	/*获得表达式中下一个元素函数,若函数运行结束时,引用变量reto为true,则表示该元素为一个运算符,其编号保存
	在引用变量retn中;否则,表示该元素为一个数字,其值保存在引用变量retn中。引用变量i表示遍历到的字符串下标*/
	if(i == 0 && op.empty() == true){
		//若此时遍历字符串第一个字符,且运算符栈为空,人为添加编号为0的标记序列
		reto = true;
		retn = 0;
		return; 
	} 
	if(str[i] == 0){
		//遍历字符为空字符,则表示字符串已经被遍历完
		reto = true;
		retn = 0;
		return; 
	}
	if(str[i] >= '0' && str[i] <= '9'){
		reto = false;
	}
	else{
		reto = true;
		if(str[i] == '+'){
			retn = 1;
		}
		else if(str[i] == '-'){
			retn = 2;
		}
		else if(str[i] == '*'){
			retn = 3;
		}
		else if(str[i] == '/'){
			retn = 4;
		}
		i += 2;
		return;
	}
	retn = 0;
	for(; str[i] != ' ' && str[i] != 0; i++){
		//若字符串未被遍历完,且下一个字符不是空格,依次遍历其后的数字
		retn *= 10;
		retn += str[i] - '0'; 
	}
	if(str[i] == ' '){
		i++;
	}
	return ;
}  

int main(){
	while(gets(str)){
		if(str[0] == '0' && str[1] == 0)
			break;
		bool retop;
		int retnum;
		int idx = 0;
		while(!op.empty()){
			op.pop();
		} //清空符号栈 
		while(in.empty()){
			in.pop();
		} //清空数字栈 
		while(true){
			getOp(retop, retnum, idx); //获取表达式中下一个元素
			if(retop == false){
				in.push((double)retnum);
			} 
			else{
				double tmp;
				if(op.empty() == true || mat[retnum][op.top()] == 1){
					op.push(retnum);
				}//运算符堆栈为空,或当前遍历到的运算符优先级大于栈顶运算符,将该运算符压入运算符堆栈 
				else{
					while(mat[retnum][op.top()] == 0){
						int ret = op.top();
						op.pop();
						double b = in.top();
						in.pop();
						double a = in.top();
						in.pop();
						
						if(ret == 1)
							tmp = a+b;
						else if(ret == 2)
							tmp = a-b;
						else if(ret == 3)
							tmp = a*b;
						else
							tmp = a/b;
						in.push(tmp); //将结果压回数字堆栈 
					}
					op.push(retnum); //将当前运算符压回运算符堆栈 
				}
			}
			if(op.size() == 2 && op.top() == 0) 
				break;
		}
		printf("%.2f\n", in.top());
	}
	return 0;
}

运行结果

在这里插入图片描述

总结

gets函数和cin的区别
while循环中的gets(str),刚开始我写的是cin>>str,运行结果不对,必须要写gets函数。因为cin遇到空格就不读了,gets是遇到换行(回车)就不读。

猜你喜欢

转载自blog.csdn.net/weixin_44332298/article/details/88034505