【7002】模拟计算机处理算术表达式过程

Time Limit: 3 second
Memory Limit: 2 MB

问题描述
     从键盘上输入算术表达式串(只含+、-、*、/运算符,允许含圆括号,运算数为整型、实型常量),输出算术表达式的值。设输入的表达式串是合法的。

Input

    输入为一行算术表达式串

Output

    输出一行,算术表达式的值(输出两位小数,整数部分按实际位数输出,最后用换行结束)。

Sample Input

    (3+2)-5*(6-1)

Sample Output

    -20.00
【题解】
用分治法来求中缀表达式:
具体过程.每层递归,都找到所有运算符里面优先级别最低的运算符。
假设这个运算符的位置为k
则把1..k-1截出来 设为x,k+1..length(s)也截出来,设为y;
然后对x和y进行相同的操作。也去找运算级别最小的运算符。。。
直到最后操作的一个字符串全是数字。然后就返回这个数字就好。
最后根据k位置的运算符。做相应的运算。
即"x" 运算符 "y";
【代码】
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <iostream>

using namespace std;

string s;

char cmp(char x, char y) //判断操作符x和操作符y,哪一个优先级大 
{
	if (x == '$')
		return '>';
	if ( (x == '*' || x == '/')	&& (y == '+' || y =='-'))//乘法和除法的优先级比加减法高 
		return '>';
	if ( (x == '+' || x == '-') && (y == '+' || y =='-')) //如果是同一优先级。则往后找运算符。因为同一优先级先找到的是后运算的 
		return '>';
	if ( (x == '*' || x == '/')	&& (y == '*' || y =='/')) //依旧是同一优先级的处理; 
		return '>';		
	return '<';
}

int find(string tt) //表示找tt这个字符串的优先级最小的操作符 
{
	int k =0;
	char now = '$'; 
	int i = 0;
	while (i <= tt.size()-1) //用i来枚举 
		{
			if (tt[i] == '(') //如果是括号的话就要跳过。因为括号里的东西一定是后算的,不能考虑优先级 
				{
					int b = 0; //这是用来匹配这个括号,当然可能有多个括号 用栈的思想来匹配 
					do
						{
							switch (tt[i])
								{
									case '(':
										b++;
										break;
									case ')':
										b--;
										break;
								}
							i++;
						}
						while (b !=0);
				}
				else
					if (tt[i] == '*' || tt[i] == '/' || tt[i] == '+' || ( tt[i] == '-' && i >0 && (tt[i-1] ==')' || (tt[i-1] >='0' && tt[i-1] <='9'))))
						{ //如果是运算符,就先和当前获得的优先级最小的运算符比较。看看是否优先级更低 
							if (cmp(now,tt[i]) == '>')
								{
									now = tt[i];//如果更低 则更新 
									k = i;
								}
							i++;
						}
						else
							i++; //不管是什么 都要递增循环变量 
		}
	return k;
}

void reducebracket(string & tss) //去掉两边的括号 表示对括号里的string进行操作 
{
	int ltss = tss.size(); //表示tss的长度 
	if (tss[0] !='(' || tss[ltss-1]!=')') //如果两边不是配对的括号就返回。 
		return;
	int b =0;
	for (int i = 1;i <= ltss-2;i++) //表示在2到l-1之间查看括号是否配对,因为可能有()+()这样的情况。 
		{
			if (tss[i] == '(')
				b++;
			if (tss[i] == ')')
				b--;
			if (b < 0)
				return;
		}
	if (b!=0)
		return;
	tss = tss.erase(ltss-1,1); //去除两边的括号 
	tss = tss.erase(0,1);	
}

double reduce( string ss)
{
	int i = 0,ls = ss.size();
	if (ls == 0) //如果长度为0,则直接返回0; 
		return 0;
	bool judge = false; //表示是否找到了运算符 
	while (i <= ls-1)
		{
			if (ss[i] == '+' || ss[i] == '*' || ss[i] == '/') //+*/都可以直接判断 
				 {
				 	judge = true;
				 	break;
				 }
				 	else //如果是减法的话,要判断它前一位是不是右括号或者是数字。因为可能是负数 
				 		if (ss[i] == '-' && i > 0 && (ss[i-1] == ')' || (ss[i-1] >='0' && ss[i-1] <='9')))
				 			{
							 	judge = true;
				 				break;
				 			}
			i++;
		}
	if (!judge) //如果没有运算符。则这个串就是一个数字。直接返回就可以了 
		{
			double x = atof(ss.c_str());
			return x;
		}
	reducebracket(ss); //如果有运算符。就先去掉两边的括号(如果有) 
	int k = find(ss); //找到运算级别最小的运算符的位置 
	
	string s1 = ss.substr(0,k); //截取这个运算符左边的"数字" 
	string s2 = ss.substr(k+1,ss.size()-s1.size()-1); //截取这个运算符右边的"数字" 
	double x = reduce(s1),y = reduce(s2),z; //对左边和右边的进行计算。 
	switch (ss[k])  //对ss[k]进行判断 根据运算符做相应的运算。 
		{
			case '+':
				z = x + y;
				break;
			case '-':
				z = x - y;
				break;
			case '*':
				z = x * y;
				break;
			case '/':
				z = x / y;
				break;
		}
	return z; //返回这个值。 
}

int main()
{
	//freopen("F:\\rush.txt","r",stdin);
	getline(cin,s);
	printf("%.2lf",reduce(s)); 
	return 0;
}


posted @ 2017-10-06 19:23  AWCXV  阅读(281)  评论(0编辑  收藏  举报