理论概念部分:
在计算机应用领域,由于运算符的优先级和结合性不同限定了计算的顺序,另外通过加括号可以改变计算顺序,使得求一个表达式的值的过程变得比较复杂。下面介绍几种求表达式值的方法。
常见的表达式表示方式是操作符(双目运算符)放在操作数的中间,这类表示表达式的方式称为中缀表达式。例如,四则混合运算式 46/2+32x(5- 17)中,除号的两个操作数46和2放置在除号的两侧,加号的两个操作数 46/2 和 32x(5-17)放置在加号的两侧。对人类
完整代码实现:
#include<iostream>
#include<map>
#include<stack>
using namespace std;
constexpr auto N = 30;
//逆波兰表达式中元素的表示方法
/*
其中,需要预先为每一个运算符指定优先级,存放在pri中,
另外,为了节省空间,定义一个共用体data存放操作数和运算符,
tag用于区分当前元素为操作数还是运算符。
*/
map<char,int>pri; //优先级
typedef struct rpn_node {
bool tag; //true:元素为操作数;false:元素为运算符
union {
int v; //操作数
char op; //运算符
}data;
}rpn[N];
//调度场算法
//定义所涉及的运算符的优先级,可根据c++中运算符的优先级表
void Init() {
pri['+'] = 6 ;
pri['-'] = 6 ;
pri['*'] = 5 ;
pri['/'] = 5 ;
pri['('] = 99 ;
pri[')'] = 99 ;
pri['$'] = 99 ;
}
//将中缀表达式infix转化为逆波兰表达式,结果存放在posfix中,n为逆波兰表达式中元素的个数
void shuntingYard(string infix, rpn& posfix, int& n) {
infix += '$', n = 0;//为infix加一个后缀
int i = 0, len = infix.length(), num = 0;
stack<char>stk;
for (i = 0; i < len; i++) {
if (isdigit(infix[i])) { //当前字符为数字
num = 0;
while (isdigit(infix[i])) //获取连续的数字所表示的数
num = num * 10 + infix[i++] - '0';
posfix[n].tag = true;//将数字加入逆波兰表达式
posfix[n++].data.v = num;
i--;
}
else { //当前字符为运算符
if (infix[i] == '(') { //( 直接入栈
stk.push(infix[i]);
continue;
}
while (!stk.empty() && pri[stk.top()] <= pri[infix[i]]) {//当前运算符与栈顶运算符进行优先级比较
if (stk.top() == '(') { //如果栈顶元素为'(',退出循环
if (infix[i] == ')') stk.pop(); //如果当前元素为')','('出栈
break;
}
posfix[n].tag = false; //将栈顶元素加入逆波兰表达式
posfix[n++].data.op = stk.top();
stk.pop();
}
if (infix[i] != ')') stk.push(infix[i]);//当前字符入栈,)除外,其让栈顶元素出栈
}
}
}
//利用表达式的逆波兰表达式求表达式的值
//返回表达式v1 op v2 的计算结果
double cal(double v1, char op, double v2) {
switch(op){
case '+':return v1 + v2;
case '-':return v1 - v2;
case '*':return v1 * v2;
case '/':return 1.0 * v1 / v2;
}
}
//计算具有n项的逆波兰表达式posfix表达式的值,结果作为返回值
double calculate(rpn posfix, int n) {
double v1, v2;
stack<double>stk;
for (int i = 0; i < n; i++) {
if (posfix[i].tag) //当前项为操作数,直接入栈
stk.push(posfix[i].data.v);
else { //当前项为运算符,从栈中取两项
v1 = stk.top(), stk.pop();
v2 = stk.top(), stk.pop();
stk.push(cal(v2, posfix[i].data.op, v1)); //计算并将计算结果入栈
}
}
return stk.top(); //最后栈顶元素即为表达式的值
}
int main() {
Init();
string infix = "46/2+32*(5-17)";
rpn r1; //学会创建结构体数组的变量
int number;
shuntingYard(infix, r1, number);
/*for (int i = 0; i < 9; i++) {
cout << r1[i].data.v << " " << r1[i].data.op << endl;
}*/
cout << calculate(r1, number);
}