问题描述:
这里限定的简单算术表达式求值问题是:用户输入一个包含“+”、“-”、“*”、“/”、正整数和圆括号的合法数学表达式,计算该表达式的运算结果。如:“2+4*(5-1)”=18。
代码示例:
#include <iostream>
#include "SqStack.cpp" //包含顺序栈类模板
using namespace std;
class ExpressClass //求表达式值类
{
char *exp; //存放中缀表达式
char postexp[MaxSize]; //存放后缀表达式
int pnum; //postexp中字符个数
public:
void Setexp(char *str); //获取一个中缀表达式
void Disppostexp(); //输出后缀表达式
void Trans(); //将算术表达式exp转换成后缀表达式postexp
bool GetValue(double &v); //计算后缀表达式postexp的值
void Trans1(); //输出将算术表达式exp转换成后缀表达式postexp的过程
bool GetValue1(double &v); //输出计算后缀表达式postexp的值的过程
};
void ExpressClass::Setexp(char *str) //获取一个中缀表达式
{
exp = str;
}
void ExpressClass::Trans() //将算术表达式exp转换成后缀表达式postexp
{
SqStackClass<char> op; //运算符栈
int i = 0, j = 0; //i、j作为exp和postexp的下标
char ch, e;
while (exp[i]) //exp表达式未扫描完时循环
{
ch = exp[i];
if (ch == '(') //判定为左括号
op.Push(ch); //将左括号进栈
else if (ch == ')') //判定为右括号
{
while (!op.StackEmpty() && op.GetTop(e) && e != '(')//将op栈中'('之前的运算符退栈并存放到postexp中
{
op.Pop(e);
postexp[j++] = e;
}
op.Pop(e); //将(退栈
}
else if (ch == '+' || ch == '-') //判定为加或减号
{
while (!op.StackEmpty() && op.GetTop(e) && e != '(')//将op栈中'('之前的所有运算符退栈并存放到postexp中
{
op.Pop(e);
postexp[j++] = e;
}
op.Push(ch); //再将'+'或'-'进栈
}
else if (ch == '*' || ch == '/') //判定为'*'或'/'号
{
while (!op.StackEmpty() && op.GetTop(e) && e != '(' && (e == '*' || e == '/'))//将op栈中'('之前的'*'或'/'运算符依次出栈并存放到postexp中
{
op.Pop(e);
postexp[j++] = e;
}
op.Push(ch); //再将'*'或'/'进栈
}
else //处理数字字符
{
while (ch >= '0' && ch <= '9') //判定为数字
{
postexp[j++] = ch;
i++; //将连续的数字放入postexp
if (exp[i]) ch = exp[i];
else break;
}
i--;
postexp[j++] = '#'; //用#标识一个数值串结束
}
i++; //继续处理其他字符
}
while (!op.StackEmpty()) //此时exp扫描完毕,栈不空时循环
{
op.Pop(e); //将栈中所有运算符退栈并放入postexp
postexp[j++] = e;
}
pnum = j; //保存postexp中字符个数
}
bool ExpressClass::GetValue(double &v) //计算后缀表达式postexp的值
{
SqStackClass<double> st; //运算数栈st
double a, b, c, d;
int i = 0;
char ch;
while (i<pnum) //postexp字符串未扫描完时循环
{
ch = postexp[i];
switch (ch)
{
case '+': //判定为'+'号
st.Pop(a); //退栈取数值a
st.Pop(b); //退栈取数值b
c = b + a; //计算c
st.Push(c); //将计算结果进栈
break;
case '-': //判定为'-'号
st.Pop(a); //退栈取数值a
st.Pop(b); //退栈取数值b
c = b - a; //计算c
st.Push(c); //将计算结果进栈
break;
case '*': //判定为'*'号
st.Pop(a); //退栈取数值a
st.Pop(b); //退栈取数值b
c = b*a; //计算c
st.Push(c); //将计算结果进栈
break;
case '/': //判定为'/'号
st.Pop(a); //退栈取数值a
st.Pop(b); //退栈取数值b
if (a != 0)
{
c = b / a; //计算c
st.Push(c); //将计算结果进栈
}
else return false; //除零错误返回false
break;
default: //处理数字字符
d = 0; //将连续的数字符转换成数值存放到d中
while (ch >= '0' && ch <= '9') //判定为数字字符
{
d = 10 * d + (ch - '0');
i++;
ch = postexp[i];
}
st.Push(d); //将数值d进栈
break;
}
i++; //继续处理其他字符
}
st.GetTop(v); //栈顶元素即为求值结果
return true;
}
void ExpressClass::Disppostexp() //输出后缀表达式
{
int i;
for (i = 0; i < pnum; i++)
cout << postexp[i];
cout << endl;
}
//=================显示求解过程========================
void ExpressClass::Trans1() //输出将算术表达式exp转换成后缀表达式postexp的过程
{
SqStackClass<char> op; //运算符栈op
int i = 0, j = 0; //i、j作为exp和postexp的下标
char ch, e;
while (exp[i]) //exp表达式未扫描完时循环
{
ch = exp[i];
if (ch == '(') //判定为左括号
{
op.Push(ch);
cout << " 运算符'" << ch << "'进栈\n";
}
else if (ch == ')') //判定为右括号
{
while (!op.StackEmpty() && op.GetTop(e) && e != '(')//将op栈中'('之前的运算符退栈并存放到postexp中
{
op.Pop(e);
postexp[j++] = e;
cout << " 运算符'" << e << "'退栈→postexp\n";
}
op.Pop(e); //将(退栈
cout << " 运算符'('退栈\n";
}
else if (ch == '+' || ch == '-') //判定为加或减号
{
while (!op.StackEmpty() && op.GetTop(e) && e != '(')//将op栈中'('之前的运算符退栈并存放到postexp中
{
op.Pop(e);
postexp[j++] = e;
cout << " 运算符'" << e << "'退栈→postexp\n";
}
op.Push(ch); //将'+'或'-'进栈
cout << " 运算符'" << ch << "'进栈\n";
}
else if (ch == '*' || ch == '/') //判定为'*'或'/'号
{
while (!op.StackEmpty() && op.GetTop(e) && e != '(' && (e == '*' || e == '/'))//将op栈中'('之前的'*'或'/'运算符依次出栈并存放到postexp中
{
op.Pop(e);
postexp[j++] = e;
cout << " 运算符'" << e << "'退栈→postexp\n";
}
op.Push(ch); //将'*'或'/'进栈
cout << " 运算符'" << ch << "'进栈\n";
}
else //处理数字字符
{
while (ch >= '0' && ch <= '9') //判定为数字
{
postexp[j++] = ch;
cout << " " << ch << "→postexp\t";
i++;
if (exp[i]) ch = exp[i]; //exp表达式未扫描完时取下一个字符
else break;
}
i--;
postexp[j++] = '#'; //用#标识一个数值串结束
cout << " postexp中加#\n";
}
i++; //继续处理其他字符
}
while (!op.StackEmpty()) //此时exp扫描完毕,栈不空时循环
{
op.Pop(e);
postexp[j++] = e;
cout << " 运算符'" << e << "'退栈→postexp\n";
}
pnum = j;
}
bool ExpressClass::GetValue1(double &v) //输出计算后缀表达式postexp的值的过程
{
SqStackClass<double> st; //运算数栈
double a, b, c, d;
int i = 0;
char ch;
while (i < pnum) //postexp字符串未扫描完时循环
{
ch = postexp[i];
switch (ch)
{
case '+': //判定为'+'号
st.Pop(a); //退栈取数值a
cout << " 运算数" << a << "退栈\t";
st.Pop(b); //退栈取数值b
cout << " 运算数" << b << "退栈\n";
c = b + a; //计算c
cout << " 计算" << b << "+" << a << "=" << c << endl;
st.Push(c); //将计算结果进栈
cout << " 运算数" << c << "进栈\n";
break;
case '-': //判定为'-'号
st.Pop(a); //退栈取数值a
cout << " 运算数" << a << "退栈\t";
st.Pop(b); //退栈取数值b
cout << " 运算数" << b << "退栈\n";
c = b - a; //计算c
cout << " 计算" << b << "-" << a << "=" << c << endl;
st.Push(c); //将计算结果进栈
cout << " 运算数" << c << "进栈\n";
break;
case '*': //判定为'*'号
st.Pop(a); //退栈取数值a
cout << " 运算数" << a << "退栈\t";
st.Pop(b); //退栈取数值b
cout << " 运算数" << b << "退栈\n";
c = b*a; //计算c
cout << " 计算" << b << "*" << a << "=" << c << endl;
st.Push(c); //将计算结果进栈
cout << " 运算数" << c << "进栈\n";
break;
case '/': //判定为'/'号
st.Pop(a); //退栈取数值a
cout << " 运算数" << a << "退栈\t";
st.Pop(b); //退栈取数值b
cout << " 运算数" << b << "退栈\n";
if (a != 0)
{
c = b / a; //计算c
cout << " 计算" << b << "/" << a << "=" << c << endl;
st.Push(c); //将计算结果进栈
cout << " 运算数" << c << "进栈\n";
}
else return false; //除零错误返回false
break;
default: //处理数字字符
d = 0; //将连续的数字符转换成数值存放到d中
while (ch >= '0' && ch <= '9') //判定为数字字符
{
d = 10 * d + (ch - '0');
i++;
ch = postexp[i];
}
st.Push(d); //数值d进栈
cout << " 运算数" << d << "进栈\n";
break;
}
i++; //继续处理其他字符
}
st.GetTop(v); //栈顶元素即为求值结果
cout << " 取栈顶数值" << v << endl;
return true;
}
void main()
{
double v;
ExpressClass obj;
char *str = "(56-20)/(4+2)";
obj.Setexp(str);
cout << "中缀表达式" << str << "转换为后缀表达式的过程:\n";
obj.Trans1();
cout << "求得的后缀表达式:"; obj.Disppostexp();
cout << "求后缀表达式的过程:\n";
obj.GetValue1(v);
cout << "求得的表达式值:" << v << endl;
}