NYOJ-0035-表达式求值

本文介绍了一种利用栈实现计算器的方法,重点讲解了如何处理运算符优先级和括号嵌套的问题,通过具体实例展示了算法的设计与实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

表达式求值

时间限制:3000 ms  |  内存限制:65535 KB
难度:4
描述
     ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在        请你帮助他来实现这个计算器吧。比如输入:“1+2/4=”,程序就输出1.50(结果保留两位小数)
输入
    第一行输入一个整数n,共有n组测试数据(n<10)。
    每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以“=”结束。这个表达式里只包含+-*/与小括号这几种     符号。其中小括号可以嵌套使用。数据保证输入的操作数中不会出现负数。
    数据保证除数不会为0
输出
    每组都输出该组运算式的运算结果,输出结果保留两位小数。
样例输入
2
1.000+2/4=
((1+2)*5+1)/4=
样例输出
1.50
4.00

 NYOJ上的题,运用栈相关的知识,开始时套用学长的框架,但细节部分仍是自己的,出错的情况会在下面说到

 请看思路:

  1.用字符串输入,建立两个栈,一个储存数字,另一个储存运算符;

  2.运算符要先建立优先级,符合四则运算的规律,防止出现1+2*3=9的情况;

  3.括号里的要先计算(我是把括号的优先级当做最低,在循环时遇到左括号直接进栈,遇右括号一直计算到运算符栈顶是左括号为 止,这样就达到了先计算括号内式子的目的,还有,注意右括号判断摆放的位置,一定是左括号在前,紧接着是右括号,后面是其他(我犯过这样的错误,(1+2)*3计算终止,调试发现运算符栈顶是右括号无法计算,亲身体验));

  4.当前 str[i] 是运算符且优先级比运算符栈顶的运算符大,直接进栈(先乘除,后加减,例子同2);

  5.当前 str[i] 是运算符且优先级比运算符栈顶的运算符小或相等,要先计算栈顶运算符,不然会出现1-2-3=2的情况;

  6.由于字符串表达式以 ' = ' 结尾,因此判断等号应在最前方,一旦遇到 ' = ' ,直接跳出循环,可以节省接下来几步判断的时间

下面是代码部分:

 
#include <stdio.h>
#include <string.h>
#include <stack>
#include <ctype.h>
#include <stdlib.h>
using namespace std;

//定义四则运算优先级:先乘除,再加减 
int priority( char ch ) {
	switch( ch ) {
		case '+':
		case '-' :
			return 1;
		case '*':
		case '/' :
			return 2;
		case '=':
			return 0;
	}
}

//将当前数字栈和运算符栈里的顶部元素进行一步运算 
void algor( stack<double>& num , stack<char>& sign ) {
	double a , b;
	char ch;
	a = num.top();
	num.pop();
	b = num.top();
	num.pop();
	ch = sign.top();
	switch( ch ) {
		case '+' :
			num.push( b+a );
			break;
		case '-' :
			num.push( b-a );
			break;
		case '*' :
			num.push( b*a );
			break;
		case '/' :
			num.push( b/a );
			break;
	}
	sign.pop();
}

int main() {
	stack<char> sign ;
	stack<double> num ;
	int n,i,len;
	double x;
	char str[1005],temp[200];
	scanf( "%d" , &n );
	while( n-- ) {
		scanf( "%s" , str );
		len = strlen(str);
		//开始遍历字符串 
		for( i=0 ; i<len ; i++ ) {
			//如果当前字符是数字 
			if( isdigit( str[i] ) ) {
				int j=0	;
				//向后遍历取得完整的数字部分 
				while( ( isdigit( str[i] ) || str[i] == '.' ) && i<len ) {
					temp[j] = str[i];
					i++;
					j++;
				}
				i--;
				//取得数字部分 
				temp[j] = '\0';
				x = atof( temp );
				//数字栈将数字进栈 
				num.push(x);
			} else {
				// '='是字符串结束标志 
				if( str[i]=='=')
					break;
				//左括号进栈 
				if( str[i] == '(' ) {
					sign.push( str[i] );
				//右括号一直运算直到碰到左括号 
				} else if( str[i] == ')' ) {
					while( sign.top() != '(' )
						algor( num , sign );
					sign.pop();
				//字符栈空或者栈底为左括号,当前运算符进栈 
				} else if( sign.empty() || sign.top() == '(' ) {
					sign.push( str[i] );
				//比较优先级,如果当前运算符优先级高,直接进栈 
				} else if( priority( str[i] ) > priority(sign.top()) ) {
					sign.push( str[i] );
				} else {
					//如果当前运算符优先级低则将运算符栈里所有比当前运算符优先级高的运算符进行运算 
					while( !sign.empty() && priority( str[i] ) <= priority(sign.top()) ) {
						algor( num , sign );
					}
					//运算完毕后当前低优先级运算符入栈 
					sign.push( str[i] );
				}
			}
		}
		//计算所有算式 
		while( !sign.empty() )
			algor( num , sign );
		//输出结果 
		printf( "%.2lf\n" , num.top() );
		//计算完毕后,运算符栈没有元素,数据栈保留着最后结果,输出后出栈 
		num.pop();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值