表达式求值,一般采用栈和队列的方式来求值,下面介绍表达式求值的两种算法。
方法一、使用两个栈,一个为操作符栈OPTR(operator)
,一个是操作数栈OPND(operand)
算法过程:
当输入 3 * ( 4 - 1 * 2 ) + 6 / ( 1 + 1 )
时,先将输入的数据存储在一个字符数组中,按照字符的顺序一个一个的处理,比如
ch = getchar()
- 1
- 2
然后根据ch
的值判断。
- 若
ch
是数字,直接压入操作数栈OPND
; - 若
ch
是'('
,直接入栈OPTR
;若ch
是')'
,若OPTR
和OPND
非空,弹出OPTR
的栈顶操作符,弹出OPND
栈顶的两个操作数,做运算,然后见个结果压入栈OPND
,直到弹出的OPTR
栈顶元素时')'
; - 若
ch
是操作符(比如+, -, *, /
),如果OPTR
栈顶元素是(
,直接入栈OPTR
,如果不是'('
且OPTR
栈非空且栈顶元素操作符的优先级大于ch
,那么弹出OPTR
的栈顶操作符,并弹出OPND
中栈顶的两个元素,做运算,将运算结果入栈OPND
,此时,重复这一步操作;否则将ch
入栈OPTR
; - 若
ch
为EOF,说明表达式已经输入完成,判断OPTR
是否为空,若非空,一次弹出OPTR
栈顶操作符,并与OPND
栈顶两个元素做运算,将运算结果入栈OPND
,最后表达式的结果即OPND
的栈底元素。
以表达式3 * ( 4 - 1 * 2 ) + 6 / ( 1 + 1 )
为例,计算过程如下所示:
OPTR | OPND | ch | 备注 |
3 | 3 | ||
* | 3 | * | |
*,( | 3 | ( | |
*,( | 3,4 | 4 | |
*,(,- | 3,4 | - | |
*,(,- | 3,4,1 | 1 | |
*,(,-,* | 3,4,1 | * | |
*,(,-,* | 3,4,1,2 | 2 | |
*,(,- | 3,4,2 | ) | OPND弹出2和1,OPTR弹出*,计算结果入栈OPND |
*,( | 3,2 | ) | OPND弹出2和4,OPTR弹出-,计算结果入栈OPND |
* | 3,2 | ) | OPTR栈顶弹出的是) |
+ | 6 | + | OPTR栈顶元素优先级大于ch,将OPND栈的3和2与OPTR的*运算,结果入栈OPND,ch入栈OPTR |
+ | 6,6 | 6 | |
+,/ | 6,6 | / | |
+,/,( | 6,6 | ( | |
+,/,( | 6,6,1 | 1 | |
+,/,(,+ | 6,6,1 | + | |
+,/,(,+ | 6,6,1,1 | 1 | |
+,/,( | 6,6,2 | ) | OPND的1和1,与OPTR的+运算,结果入栈OPND |
+,/ | 6,6,2 | ) | |
+ | 6,3 | 表达式已经输入完成,OPTR非空,继续计算。OPND的2和6,OPTR的/运算 | |
9 | 计算结果 |
#include <iostream>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cmath>
using namespace std;
char s[1000];
int g_pos; // 字符数组的下标
/* 字符转数字 */
double Translation(int & pos)
{
double integer = 0.0; // 整数部分
double remainder = 0.0; // 余数部分
while (s[pos] >= '0' && s[pos] <= '9')
{
integer *= 10;
integer += (s[pos] - '0');
pos++;
}
if (s[pos] == '.')
{
pos++;
int c = 1;
while (s[pos] >= '0' && s[pos] <= '9')
{
double t = s[pos] - '0';
t *= pow(0.1, c);
c++;
remainder += t;
pos++;
}
}
return integer + remainder;
}
/* 返回运算符级别 */
int GetLevel(char ch)
{
switch (ch)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '(':
return 0;
case '#':
return -1;
};
}
/* 对两个数进行运算 */
double Operate(double a1, char op, double a2)
{
switch (op)
{
case '+':
return a1 + a2;
case '-':
return a1 - a2;
case '*':
return a1 * a2;
case '/':
return a1 / a2;
};
}
/* 利用两个栈进行模拟计算 */
double Compute()
{
stack<char> optr; // 操作符栈
stack<double> opnd; // 操作数栈
optr.push('#'); //置于符栈顶
int len = strlen(s);
bool is_minus = true; // 判断'-'是减号还是负号, true表示负号
for (g_pos = 0; g_pos < len;)
{
//1. 负号
if (s[g_pos] == '-' && is_minus) // 是负号
{
opnd.push(0);
optr.push('-');
g_pos++;
}
//2. 是右括号 )
else if (s[g_pos] == ')')
{
is_minus = false;
g_pos++;
while (optr.top() != '(')
{
double a2 = opnd.top();
opnd.pop();
double a1 = opnd.top();
opnd.pop();
char op = optr.top();
optr.pop();
double result = Operate(a1, op, a2);
opnd.push(result);
}
optr.pop(); // 删除'('
}
//3. 数字
else if (s[g_pos] >= '0' && s[g_pos] <= '9')
{
is_minus = false;
opnd.push(Translation(g_pos));
}
//4. ( 左括号
else if (s[g_pos] == '(')
{
is_minus = true;
optr.push(s[g_pos]);
g_pos++;
}
//5. + - * / 四种
else
{
while (GetLevel(s[g_pos]) <= GetLevel(optr.top())) //当前优先级小于栈尾优先级
{
double a2 = opnd.top();
opnd.pop();
double a1 = opnd.top();
opnd.pop();
char op = optr.top();
optr.pop();
double result = Operate(a1, op, a2);
opnd.push(result);
}
optr.push(s[g_pos]);
g_pos++;
}
}
while (optr.top() != '#')
{
double a2 = opnd.top();
opnd.pop();
double a1 = opnd.top();
opnd.pop();
char op = optr.top();
optr.pop();
double result = Operate(a1, op, a2);
opnd.push(result);
}
return opnd.top();
}
int main()
{
while (cin >> s)
cout << "结果为:" << Compute() << endl << endl;
return 0;
}