/*
问题:简单的计算器,读入只含 +,-,*,/的非负整数计算式,计算表达式的值
输入:
若干测试用例,每个测试用例占1行,每行<=200个字符,整数和字符之间用一个空格分隔。无非法表达式。遇只含有0的一行时,结束输出
输出:
输出1行该表达式的值,保留2位小数
输入:
(1 + 2) 1 2 +
(4 + 2 * 5 - 7 / 11) 4 2 5 * + 7 11 / -
0
输出:
3.00
13.36
思路:用栈,后缀表达式,首先*和/的优先级较高,碰到需要优先处理,其实就是中缀表达式转换为后缀表达式,然后每次栈顶为运算符时,
取栈顶元素A,和次栈顶元素B,计算 B 运算符 A 即可,得到的计算结果再存入栈
问题转化为:中缀转后缀
好像是从右向左扫描
7 / 11 ->
关键:
1设定数字栈和运算符栈,
遇到数字直接压入数字栈中
遇到运算符,{若当前运算符#比栈顶运算符优先级小 或者 栈为空,则压入当前运算符
{否则,从数字栈中弹出栈顶元素A,次栈顶元素B,计算 B # A,将计算后的结果压入数字栈中
需要为该表达式设定运算符(和),两者的优先级最低,表示表达式的开始与结束
循环终止条件:运算符栈中仅剩2个运算符,并且栈顶运算符为")"时,比较优先级应该循环比较
2由于字符串中有空格,而scanf回跳过不处理,认为是下一次输出,因此对于含有空格或制表符的字符串用gets函数,而不是scanf
char* gets(char* str);
3打印2位小数用printf("%.2f",i);不是%.2d,这表示整数
%n,mf:即输出总共n位,其中有m位小数,-号是右端补空格
4易错:11看成了2个1,应该以空格为分隔符(截取的字符串),来判定数字
*/
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <string.h>
#include <map>
using namespace std;
bool isNumber(char c)
{
if(' '==c)
{
return false;
}
char sNum[11] = {'0','1','2','3','4','5','6','7','8','9'};
int i = 0;
while('\0'!=sNum[i])
{
//if(c=sNum[i])//关键是==而不是=
if(c==sNum[i])
{
return true;
}
i++;
}
return false;
}
bool isOperator(char c)
{
if(' '==c)
{
return false;
}
char sOpe[7] = {'(',')','+','-','*','/'};
int i = 0;
while('\0'!=sOpe[i])
{
//if(c=sOpe[i])
if(c==sOpe[i])
{
return true;
}
i++;
}
return false;
}
int my_atoi(char c)
{
switch(c)
{
case '0':return 0;
case '1':return 1;
case '2':return 2;
case '3':return 3;
case '4':return 4;
case '5':return 5;
case '6':return 6;
case '7':return 7;
case '8':return 8;
case '9':return 9;
default:
return -999;
}
return -999;
}
int main(int argc,char* argv[])
{
//设定优先级,+-一样,()一样,/*一样
map<char,int> mMap;
mMap.insert(make_pair<char,int>('(',1));
mMap.insert(make_pair<char,int>(')',1));
mMap.insert(make_pair<char,int>('+',2));
mMap.insert(make_pair<char,int>('-',2));
mMap.insert(make_pair<char,int>('*',3));
mMap.insert(make_pair<char,int>('/',3));
char sInput[201];
//关键是1有空格,计算机就认为你重新输入了,必须扣除这种情况
//while(EOF!=scanf("%s",sInput))
while(gets(sInput))
{
stack<char> stackOpe;//运算符栈
//为其添加开始标记(
stackOpe.push('(');
//stack<int> stackNum;//运算数栈
//易错,由于保留两位小数,数字栈的类型为double
stack<double> stackNum;
int i = 0;
//必须在最后给其添加')'
while('\0'!=sInput[i])
{
/*如果运算符栈只剩2个元素,并且栈顶为,')',也退出循环
if(2==stackOpe.size() && ')'==stackOpe.top())
{
break;
}
*/
bool isNumbe = false;
bool isOp = false;
if(' '==sInput[i])
{
i++;
continue;
}
//获取连续的数字
int retn = 0;
if(sInput[i] >= '0' && sInput[i] <= '9')
{
while(sInput[i] >= '0' && sInput[i] <= '9')
{
retn *= 10;
retn += sInput[i] - '0';
isNumbe = true;
i++;
}
i--;//确保拿到的是数字
}
//其余默认为运算符
else
{
isOp = true;
}
//数字进数字栈
if(isNumbe || isNumber(sInput[i]))
{
//stackNum.push(my_atoi(sInput[i]));
//stackNum.push(my_atoi(retn));
stackNum.push(retn);
i++;
//如果这是最后一个数字,则在运算符栈中添加')'
if('\0'==sInput[i])
{
sInput[i] = ')';
sInput[i+1] = '\0';
}
}
//运算符进运算符栈
else if(isOp || isOperator(sInput[i]))
{
//如果栈空,直接压入该运算符
if(stackOpe.empty())
{
stackOpe.push(sInput[i]);
i++;//计数器累加
}
else
{
//如果当前运算符的优先级比栈顶运算符的优先级要高,则进栈,相同优先级不进栈
map<char,int>::iterator itFind = mMap.find(sInput[i]);
if(itFind->second > (mMap.find(stackOpe.top()))->second)
{
stackOpe.push(sInput[i]);
i++;
}
//如果是栈顶优先级高 >= 当前运算符优先级,则弹出栈顶元素和次栈顶元素,计算结果 1 + 2全部输入完成后,它没有计算,因此需要给定最低的两个运算符
else
{
double iBackNum = stackNum.top();
stackNum.pop();
double iFrontNum = stackNum.top();
stackNum.pop();
double iRes = 0.0;
switch(stackOpe.top())
{
case '+':
iRes = (iFrontNum + iBackNum)*1.0;
break;
case '-':
iRes = (iFrontNum - iBackNum)*1.0;
break;
case '*':
iRes = (iFrontNum * iBackNum)*1.0;
break;
case '/':
iRes = (iFrontNum / iBackNum)*1.0;
break;
//如果是"("或者是")"
default:
break;
}
//i++;//由于要循环遍历,计数器不变,仍停留在当前运算符,循环与前面的运算符比较
//将计算后的结果压入数字栈
stackNum.push(iRes);
//易错,需要将栈顶高优先级操作符弹出,将当前低优先级操作进栈
stackOpe.pop();
//stackOpe.push(sInput[i]);
if('('==stackOpe.top() && ')'==sInput[i])
{
break;
}
}//else
}//else
}//else if
}//for
printf("%.2f\n",stackNum.top());
}
system("pause");
getchar();
return 0;
}