参考王道计算机机试指南
利用堆栈对表达式求值
1.设立两个堆栈,一个用于保存运算符,一个用于保存数字
2.在表达式的首位添加标记运算符,该运算符的优先级最低
3.从左至右遍历表达式,若遍历到运算符,则将该运算符与栈顶运算符进行比较,若栈顶运算符的优先级低或栈为空栈,则将运算符入栈。遍历字符串中的下一个元素
4.若栈顶运算符优先级大于当前遍历到的运算符的优先级,将运算符栈栈顶元素弹出栈,并从数字栈弹出两个数字,完成相应的运算后将结果压入数字栈,
5.若遍历到数字,则直接将数字压入数字栈
6.若运算符栈中只有两个元素,且栈顶元素为我们标记的运算符,那么表达式结束。数字栈中只有一个数字,就是我们要求的答案
#include <stack>
#include <stdio.h>
using namespace std;
char str[220];//保存表达式字符串
int mat[][5] = {//优先级矩阵,若mat[i][j]==1,则表示i号运算符优先级大于j号
//运算符,运算编码规则为+为1号,-为2号,*为3号,/为4号,我们人为添加的为0号
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
};
stack<int> op;//运算栈符,保存运算符编号
stack<double> in;//数字栈
void getOp(bool &reto,int &retn,int &i)//获取表达式中下一个元素函数
{
if(i == 0&&op.empty() == true||str[i] == 0)//若此时遍历字符串第一个字符,且运算栈为空,我们人为添加编号为0的标记字符
{
reto = true;//为运算符
retn = 0;//编号为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;//i递增,跳过该运算符和该运算符后的空格
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)//若输入只有一个0,则退出
break;
bool retop;
int retnum;
int idx = 0;//定义遍历到的字符串下标,初始值为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;
}