基本思路
一、中缀表达式求值分两大步:
- 1、将中缀表达式转换为后缀表达式,统一形式,用空格做间隔;
- 2、后缀表达式求值。
二、中缀表达式转换为后缀表达式的思路
-
1、处理空格:输入可能不规范,统一将空格全部删除;此时运算符和括号成为数字的间隔符,方便处理。
-
2、处理单目运算符正负号±;因为它是单目运算符,运算等级要高,使用!来代表-;+号则忽略
-
3、查找运算符及间隔符
- A、运算符不是第一个,则表达式第一个是运算数,运算数直接加入后缀表达式;
- B、运算符是第一个,则要处理运算符:
- B.1、第一个可定是运算符,根据优先等级,确认之前的预备运算符是否出栈,
- B.2、将新的运算符入栈(由于这个有好几种情况需要分情况处理)
- B.3、如果有左括号,左括号右面~标记一下,查找对应的右括号,递归调用运算符处理函数
- C、直到中缀表达式的结尾为止。结尾处用空格来区分。
- D、如果是第一个,而没有有效的运算符,那么就到结尾了
-
4、关于()的循环:
- A、遇到(,则从(的下一个字符开始,递归调用中缀转换为后缀的函数。
- B、遇到), 则跳出当前的递归层。
三、后缀表达式的求值
- 1、将后缀表达式的内容,根据类型压栈和出栈:
如果为数值则压栈;
如果为运算符,则将运算符对应的运算数出栈;计算结果压栈。 - 2、重复此过程,直到表达式读取结束,此时栈内有一个数,即为结果。
四、定义一个全局unorder_map,用来记录不同运算符的优先级。
程序主体:
#include<stack>
#include<string>
#include<iostream>
#include<sstream>
#include<vector>
#include<functional>
#include<unordered_map>
#include<cmath>
using std::unordered_map;
using std::function;
using std::string;
using std::stack;
using std::cin;
using std::cout;
using std::endl;
using std::vector;
//使用类型别名,方便处理不同的类型
typedef double ValueType;
//定义基本的函数操作 加、减、乘、除及指数运算;此处使用了lambd表达式和函数
auto add = [](const ValueType &lhs, const ValueType &rhs)->ValueType {
return lhs + rhs; };
auto minus = [](const ValueType &lhs, const ValueType &rhs)->ValueType {
return lhs - rhs; };
auto multi = [](const ValueType &lhs, const ValueType &rhs) {
return lhs * rhs; };
ValueType divide(const ValueType &lhs, const ValueType &rhs) {
if (rhs == 0)
{
throw std::exception("Divisor is zero.");
return 0;
}
else
return (rhs / lhs);
}
//定义函数调用的字典,使用了可调用对象
unordered_map<char, function<ValueType(const ValueType&,const ValueType&)>> Binops = {
{
'+',add},{
'-',minus},{
'*', multi},{
'/',divide},{
'^',std::powl