一、问题描述
算符优先法:根据运算符优先关系来实现对表达式进行编译执行,为简单起见只讨论四则运算
优先级表格如下:
二、算法描述
- 设置两个栈,操作数栈opnd和操作符栈optr
- 在optr栈底加入一个“=”
- 在输入流中读入一个字符ch,循环执行 ,直到求出表达式的值
- 取出optr的栈顶optrTop,当optrTop和ch同时=“=”,整个表达式求值完毕,opnd栈顶元素为表达式值
- 若ch不是操作符,将字符放回输入流,读操作数operand,加入opnd栈,读入下一字符ch
- 若ch是操作符,则比较ch和optrTop的优先级:
optrTop<ch ch入optr栈,读入下一字符ch
optrTop>ch 从opnd栈中弹出两个数,弹出optrTop,执行运算后结果放入opnd栈中
optrTop为”)”且ch=“(” 弹出optrTop,读入下一字符ch
optrTop e ch 出现错误,停止执行
三、参考代码
- 定义栈类
class AStack //栈模板
{
protected:
int count;
int maxsize;
T* elems;
void init(int size);
bool full() const;
public:
AStack(int size = 2000); //定义栈大小
virtual ~AStack(); //析构函数
bool Empty() const; //判断是否空栈
void Clear(); //清空栈
void push(const T &a) ; //入栈
void pop(T& b); //出栈
void top(T& e) const; //取栈顶元素
};
- 执行运算的类
class Caculator {
private:
static bool IsOperator(char ch); //判断是否操作符
static char JudgePriority(char thetal, char theta2); //判断操作符优先级
static double Operate(double left, char theta, double right); //执行计算操作
static void GetTwoOpra(AStack<double>& opnd, double& left, double& right); //从栈中弹出两个操作数
static void JudgeEnter(char ch);
public:
Caculator() { }; //构造函数
virtual ~Caculator() {}; //析构函数
static void Run(); //实际运行函数
};
- 实际运行主函数
void Caculator::Run() {
AStack<double> opnd; //构建操作数栈
AStack<char> optr; //构建操作符栈
optr.push('='); //操作符栈底先放入一个等号
char ch;
char OptrTop; //操作符栈的栈顶元素
double Operand; //操作数
char theta; //操作符
ch = cin.get();
while ((optr.top(OptrTop), OptrTop!='=') || ch!='=')
{
if (ch == ' ') { ch = cin.get(); continue; }
if (!IsOperator(ch)) //不是操作数就入操作数栈,继续往后读
{
temp1 = 0;
cin.putback(ch);
cin >> Operand;
opnd.push(Operand);
ch = cin.get();
if (ch == ' ') { ch = cin.get(); continue; }
JudgeEnter(ch);
}
else
{
if ((temp1 == 1 && ch == '+') || (temp1 == 1 && ch == '-')) { //如果左括号旁边是正号或负号,往栈里压一个0,temp1重新为0
opnd.push(0);
temp1 = 0; }
else temp1 = 0;
switch (JudgePriority(OptrTop, ch))
{ //是操作符就判断该操作符与操作符栈顶的操作符的优先级
case'<': //优先级低,就进栈,继续往后读
optr.push(ch);
ch = cin.get();
JudgeEnter(ch);
break;
case '=': //操作符优先级相等,从操作符栈中弹出,继续往后读
optr.pop(OptrTop);
ch = cin.get();
JudgeEnter(ch);
break;
case'>': //优先级高,从操作数栈中弹出两个操作数进行运算,结果放入操作数栈中
double left, right;
GetTwoOpra(opnd, left, right);
optr.pop(theta);
opnd.push(Operate(left, theta, right));
break;
case'e': //读取的不是规范的操作符,错误提示
cout << "操作符匹配错" << endl;
system("pause");
exit(1);
}
}
}
opnd.top(Operand); //读操作数栈的栈顶元素,输出计算结果
cout << "表达式值为:" << Operand << endl;
}
四、总结
总的来说,实现并不难,关键是操作符优先级的比较和表达式各种情况的考虑,对熟悉栈的搭建和应用很有帮助,应尽量独立完成。