最近在做个C++课设,需要根据输入的表达式计算出结果。本人是学Android的,感觉这算法经常用到,就用Java实现了一遍。
我们平时接触的表达式是中缀表达式,如:12 * ( 8 - 3 ) - 20 。我们很简单就能算出结果为40,但计算机不行,我们要告诉它怎么算,就需要把中缀表达式转换为后缀表达式了。
基本思路:顺序扫描中缀表达式,当读入一个运算分量时就立即输出;而读入一个运算符时,先将它放进一个运算符栈中,一直等到这个运算符的两个运算分量都读到后,才输出。但运算符的优先级不同,需要遵守下面的规则:
- 读到运算分量,直接输出;
- 栈为空时,读到操作符,直接进栈;
- 左括号的优先级被视为比所有运算符低,读到左括号,直接进栈;
- 读到右括号,把栈中左括号上面的元素输出,并把左括号弹出;
- 读到其他运算符,输出所有优先级大于或等于该运算符的栈顶元素;
- 最后把栈中剩余的元素一一输出。
例如用上面表达式举例:12 * ( 8 - 3 ) - 20
中缀表达式 | 运算符栈(顶--底) | 后缀表达式 |
12 * ( 8 - 3 ) - 20 | ||
* ( 8 - 3 ) - 20 | 12 | |
( 8 - 3 ) - 20 | * | 12 |
8 - 3 ) - 20 | ( * | 12 |
- 3 ) - 20 | ( * | 12 8 |
3 ) - 20 | - ( * | 12 8 |
) - 20 | - ( * | 12 8 3 |
- 20 | * | 12 8 3 - |
20 | - | 12 8 3 - * |
- | 12 8 3 - * 20 | |
12 8 3 - * 20 - |
ps. 后缀表达式不包含左右括号的。
代码如下:
/**
* 中缀表达式转换为后缀表达式
* @param infix 中缀表达式
* @return 返回后缀表达式
*/
List<String> infix2Postfix(List<String> infix) {
List<String> postfix = new ArrayList<>();
Stack<String> stack = new Stack<>();
int len = infix.size();
String temp;
for(int i = 0; i < len; i++) {
temp = infix.get(i);
if(temp.equals(" "))
continue;
if(temp.equals(LEFT_BRACKET)) {
stack.push(temp);
} else if (temp.equals(RIGHT_BRACKET)) {
while(!stack.peek().equals(LEFT_BRACKET)) {
postfix.add(stack.pop());
}
stack.pop(); // 把左括号弹出
} else {
if(!isOperator(temp)) { // 若为操作数
postfix.add(temp);
} else {
// 从栈中弹出所有优先级比当前运算符高的运算符, 并放进队列中
while(!stack.isEmpty()
&& compareOperatorPriority(stack.peek(), temp) >= 0) {
postfix.add(stack.pop());
}
stack.push(temp); // 操作符进栈
}
}
}
// 把栈中的所有元素弹出, 放进队列中
while(!stack.isEmpty()) {
postfix.add(stack.pop());
}
return postfix;
}
接下来就是由后缀表达式求值了。
基本思路:顺序扫描后缀表达式,读到运算分量时,将它放进栈中;当读到运算符时,就从栈中弹出两个运算分量进行计算,再把结果压进栈中。扫描到结束,栈顶元素就是所求表达式的值。
还是拿上面的例子来举例:
后缀表达式 | 运算分量栈(顶--底) | 进行的计算 |
12 8 3 - * 20 - | ||
8 3 - * 20 - | 12 | |
3 - * 20 - | 8 12 | |
- * 20 - | 3 8 12 | |
* 20 - | 5 12 | 8 - 3 = 5 压进栈 |
20 - | 60 | 12 * 5 = 60 压进栈 |
- | 20 60 | |
40 | 60 - 20 = 40 压进栈 | |
40 | 计算结束 |
代码如下:
/**
* 由后缀表达式计算表达式的结果
* @param postfix 后缀表达式
* @return 返回表达式的结果
*/
double calculate(List<String> postfix) {
Stack<Double> stack = new Stack<>();
int len = postfix.size();
String temp;
for(int i = 0; i < len; i++) {
temp = postfix.get(i);
if(!isOperator(temp)) { // 若为操作数
stack.push(Double.parseDouble(temp));
} else {
double val = 0;
double num1 = stack.pop();
double num2 = stack.pop();
switch (temp) {
case ADD:
val = num2 + num1;
break;
case SUB:
val = num2 - num1; // 注意顺序哦!
break;
case MUL:
val = num2 * num1;
break;
case DEV:
val = num2 / num1;
break;
default:
break;
}
stack.push(val);
}
}
return stack.pop();
}
附上Demo:Demo