表达式求值,一般采用栈和队列的方式来求值,下面介绍表达式求值的两种算法。
方法一、使用两个栈,一个为操作符栈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; }