这是清华大学邓俊辉数据结构(C++)中的一个案例,通过使用栈这种数据结构,完成了较为复杂的表达式求值问题,以下代码是我整理改编而成,能够完成加减乘除,乘方、阶乘的运算,以及括号的处理。
在这里,我使用到了C++ STL 中的容器stack。
#include<iostream>
#include<stack>
#include<cmath>
#include<cstdlib>
#include<cstring>
using namespace std;
#define N_OPTR 9
//建立两个栈,一个存储数字,一个存储符号
stack<float> opnd;//存储数字
stack<char> optr;//存储字符
typedef enum { //通过枚举给每一个运算符一个编号
ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE
} Operator;
const char pri[N_OPTR][N_OPTR] = //运算符优先级表
{
/* |-------------------- 当 前 运 算 符 --------------------| */
/* + - * / ^ ! ( ) \0 */
/* -- + */ '>', '>', '<', '<', '<', '<', '<', '>', '>',
/* | - */ '>', '>', '<', '<', '<', '<', '<', '>', '>',
/* 栈 * */ '>', '>', '>', '>', '<', '<', '<', '>', '>',
/* 顶 / */ '>', '>', '>', '>', '<', '<', '<', '>', '>',
/* 运 ^ */ '>', '>', '>', '>', '>', '<', '<', '>', '>',
/* 算 ! */ '>', '>', '>', '>', '>', '>', ' ', '>', '>',
/* 符 ( */ '<', '<', '<', '<', '<', '<', '<', '=', ' ',
/* | ) */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
/* -- \0 */ '<', '<', '<', '<', '<', '<', '<', ' ', '='
};
Operator convert(char s) //返回枚举类型
{
switch (s)
{
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;
}
}
bool isdigit(char s) //判断读取到的字符是否是数字
{
if ((s - '0') <= 9 && (s - '0') >= 0) return true;
else return false;
}
float calcu(float popnd) //阶乘单目运算
{
if (popnd == 1) return 1;
return popnd * calcu(popnd - 1);
}
float calcu(float a, char op, float b) //普通双目运算
{
switch (op)
{
case '+': return (a + b); break;
case '-': return (a - b); break;
case '*': return (a*b); break;
case '/': return (a / b); break;
case '^': return (pow(a, b)); break;
default: exit(-1); break; //表达式错误,直接返回异常
}
}
char orderBetween(char s1, char s2) 判断栈顶运算符与正在读取到的运算符优先级
{
return pri[convert(s1)][convert(s2)];
}
void readNum(char *& s) //处理数字,尤其是如23这种连在一块的数字
{
opnd.push(static_cast<float>(*s - '0'));
while (isdigit(*(++s)))
{
float res = opnd.top() * 10 + *s - '0';
opnd.pop();
opnd.push(res);
}
if (*s != '.') return; //判断是否有小数点
float fration = 1; //进行小数点后面运算
while (isdigit(*(++s)))
{
float res2 = opnd.top() + (*s - '0')*(fration /= 10);
opnd.pop();
opnd.push(res2);
}
}
float evalue(char *s)
{
optr.push('\0'); //这个‘/0’与字符串末尾‘/0’呼应
while (!optr.empty())
{
if (isdigit(*s))
{
readNum(s);
}
else
{
switch (orderBetween(optr.top(), *s)) //不同优先级处理
{
case '<':
{
optr.push(*s); s++;
} break;
case '>':
{
char op = optr.top();
optr.pop();
if (op == '!')
{
float popnd = opnd.top();
opnd.pop();
opnd.push(calcu(popnd));
}
else
{
float popnd1 = opnd.top();
opnd.pop();
float popnd2 = opnd.top();
opnd.pop();
opnd.push(calcu(popnd1, op, popnd2));
}
} break;
case '=':
{
optr.pop(); s++;
} break;
default: exit(-1);
}
}
}
return opnd.top();
}
int main()
{
char test[100];
cin >> test; //输入字符串
cout << evalue(test);
return 0;
}