这个问题的关键在于,中缀表达式的计算顺序与运算符有关,并不是单纯的从左至右的计算。而后缀表达式的计算优先级正好是从左至右,可以将中缀转后缀的逻辑运用在中缀表达式的计算中。
中缀转后缀表达式算法(机算):
- 初始化一个栈:由于暂时还不能确定运算顺序的运算符,所以需要从左到右处理各个元素,直到末尾;
- 遇到操作数:直接加入后缀表达式;
- 遇到界限符:遇到"(“直接入栈,遇到”)",则依次弹出栈内运算符并加入后缀表达式,直到弹出 "(“为止,注意”("不加入后缀表达式;
- 遇到运算符;依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到"("或栈空则停止。之后再把当前运算符入栈。
机器实现中缀表达式计算的算法如下:
- 初始化两个栈,操作数栈和运算符栈;
- 若扫描到操作数,则压入操作数栈;
- 若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈(每当弹出一个运算符时,就需要再弹出两个操作栈的栈顶元素并执行相应运算,运算结果再压回操作数栈)。
理解了上面的两个算法之后,就可以应用到本题中来。
代码解析
根据题目可知,输入的表达式中会出现的字符有这样三种:数字、空格、运算符。
当遇到空格的时候,说明前面要么是数字,要么是运算符;
当遇到一个完整数据的时候,则压入栈中;
当遇到一个运算符的时候,则需要比较当前运算符和运算符栈顶元素的优先级。
分析完毕之后就可以开始写代码了,下面分段介绍代码:
字符数组buf: 用于保存输入的表达式,C风格的字符串;
字符串num: 用于保存数字,数字可能不止一位数,因此用字符串保存;
字符串expr: 用于将字符串数组转换成C++风格的字符串;
操作数栈NumStack: 保存操作数;
运算符栈SignStack: 保存运算符;
map类型priority: 给运算符设置优先级,后续在算法中会根据优先级来判断如何操作,在运算符中加入一个结束符,结束符的优先级设为最低,这样可以保证在遇到结束符之后将前面所有的式子都计算完成。
char buf[300];
int i;
double add_num, sum = 0;
string num = "", expr;
stack<double> NumStack;
stack<char> SignStack;
map<char, int> priority