栈应用-中缀表达式求值
思路
准备两个栈容器,一个填充数值A, 一个填充符号B, 首先向B中填充一个\0
,然后扫描字符串填充元素, 若当前扫描元素为符号时,共有三种情况:
- 当前栈中操作符的优先级小于当前元素, 将当前元素填充到B中
- 当前栈中操作符的优先级等于当前元素, 将B中栈顶元素弹出,字符串中的秩 +1
- 当前栈中操作符的优先级大于当前元素, 弹出操作符和操作数,进行计算,再将计算结果push到A栈容器, 继续比对栈中操作符的优先级和当前元素的优先级, 直到出现
情况1
, 字符串的秩才会 +1
优先级情况如下图:
当字符串扫描完成, B栈容器会被清空, C中唯一的一个元素即为计算的值
下图为简易流程图:
代码实现
#include <iostream>
using namespace std;
#include <stack>
#include <cmath>
#define N_OPTR 9
typedef enum
{
ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE,
}Operator;
//加、减、乘、除、乘方、阶乘、左括号、右括号、起始符与终止符
const char pri[N_OPTR][N_OPTR] =
{ //运算符优先等级 [栈顶] [当前]
/* |-------------------- 当 前 运 算 符 --------------------| */
/* + - * / ^ ! ( ) \0 */
/* -- + */ '>', '>', '<', '<', '<', '<', '<', '>', '>',
/* | - */ '>', '>', '<', '<', '<', '<', '<', '>', '>',
/* 栈 * */ '>', '>', '>', '>', '<', '<', '<', '>', '>',
/* 顶 / */ '>', '>', '>', '>', '<', '<', '<', '>', '>',
/* 运 ^ */ '>', '>', '>', '>', '>', '<', '<', '>', '>',
/* 算 ! */ '>', '>', '>', '>', '>', '>', ' ', '>', '>',
/* 符 ( */ '<', '<', '<', '<', '<', '<', '<', '=', ' ',
/* | ) */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
/* -- \0 */ '<', '<', '<', '<', '<', '<', '<', ' ', '='
};
void readNumber(char* &s, stack<double> &opnd)
{
opnd.push((double)(*s - '0'));
double temp = 0;
while (isdigit(*(++s)))
{
temp = opnd.top();
opnd.pop();
opnd.push(temp * 10 + (*s - '0'));
}
if ('.' != *s)
{
return;
}
while (isdigit(*(++s)))
{
temp = opnd.top();
opnd.pop();
double fraction = 1;
opnd.push(temp + (*s - '0') * (fraction / 10));
}
}
Operator optr2rank(char op)
{
switch (op)
{
case '+':
return ADD;
break;
case '-':
return SUB;
break;
case '*':
return MUL;
break;
case '/':
return DIV;
break;
case '^':
return POW;
break;
case '!':
return FAC;
break;
case '(':
return L_P;
break;
case ')':
return R_P;
break;
case '\0':
return EOE;
break;
}
}
char orderBetween(char p1, char p2)
{
return pri[optr2rank(p1)][optr2rank(p2)];
}
int fac(int n)
{
int i = 1;
while (n)
{
i *= n;
n--;
}
return i;
}
//执行一元计算
double calcu(char op, double pOpnd)
{
switch (op)
{
case '!':
return (double)fac((int)pOpnd);
break;
default:
exit(-1);
break;
}
}
//执行二元计算
double calcu(int pOpnd1, char op, int pOpnd2)
{
switch (op)
{
case '+':
return pOpnd1 + pOpnd2;
break;
case '-':
return pOpnd1 - pOpnd2;
break;
case '*':
return pOpnd1 * pOpnd2;
break;
case '/':
if (!pOpnd2)
{
exit(-1);
}
else
{
return pOpnd1 / pOpnd2;
}
break;
case '^':
return (double)pow(pOpnd1, pOpnd2);
break;
default:
exit(-1);
break;
}
}
double evaluate(char* s)
{
stack<double> opnd; stack<char> optr;
optr.push('\0');//所有操作符执行完成的标志
while (!optr.empty())
{
if (isdigit(*s))
{
readNumber(s, opnd);
}
else
{
switch (orderBetween(optr.top(), *s))
{
case '<':
{
optr.push(*s);
s++;
break;
}
case '>':
{
char op = optr.top();
optr.pop();
if ('!' == op)//若属于一元操作符
{
double pOpnd = opnd.top();
opnd.pop();
opnd.push(calcu(op, pOpnd));
}
else
{
double pOpnd2 = opnd.top(); opnd.pop();
double pOpnd1 = opnd.top(); opnd.pop();
opnd.push(calcu(pOpnd1, op, pOpnd2));
}
break;
}
case '=':
{
optr.pop();
s++;
break;
}
}
}
}
double ret = opnd.top();
return ret;
}
int main()
{
char arr[] = { "(1+2^3!-4)*(5!-(6-(7-(89-0!))))" };
double ret = evaluate(arr);
cout << "ret = " << ret << endl;
system("pause");
return 0;
}
运行结果: