表达式求值计算,如计算1+((2+3)*4)-5的值。
我的思路是先把表达式转换为逆波兰表达式,因为逆波兰表达式更加符合计算机的处理逻辑,把表达式转换为逆波兰表达式的算法如下:
- 初始化两个栈:运算符栈s2和储存中间结果的栈s1;
- 从左至右扫描中缀表达式;
- 遇到操作数时,将其压s1;
- 遇到运算符时,比较其与s2栈顶运算符的优先级:
- 如果s2为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
- 否则,若优先级比栈顶运算符的高,也将运算符压入s2(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
- 否则,将s2栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s2中新的栈顶运算符相比较;
- 遇到括号时:
- 如果是左括号“(”,则直接压入s2;
- 如果是右括号“)”,则依次弹出s2栈顶的运算符,并压入s1,直到遇到左括号为止,此时将这一对括号丢弃;
- 重复步骤2至5,直到表达式的最右边;
- 将s2中剩余的运算符依次弹出并压入s1
后缀表达式求值的算法如下:
首先定义一个栈:S3,在该栈中存放最终表达式的值。从左到右遍历S1,然后按照如下规则操作S3:
(1)如果遇到的是数字,将数字压入S3中;
(2)如果遇到单目运算符(运算对象只有一个的运算符,如:或(|)、与(&)等),取S3栈顶一个元素进行单目运算,将结果再次压入S3中;
(3)如果遇到双目运算符(运算对象有两个的运算符,如:加(+)、赋值(=)等),取S3栈顶两个元素(先出栈的在左,后出栈的在右)进行 双目运算,将结果再次压入S3中;
按照上面3条规则遍历完S1,那么最后S3中的值就是逆波兰表达式的值了。
下面是我用java的代码实现
package com.sun.calculation;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
/***
* 中缀表达式计算例如1+((2+3)*4)-5
* 实现思路就是先把中缀表达式转换为逆波兰表达式
* 然后再对逆波兰表达式表达式进行计算
* @author swh
*
*/
public class ExpressionComputation {
/***
* 先把中缀表达式转换为后缀表达式
* 再对后缀表达式进行计算
* @param expression 中缀表达式
* @return
*/
public static int computation(String expression) {
return getRpnValue(getRpn(expression));
}
/***
* 中缀表达式转换为后缀表达式
* @param expression
* @return
*/
private static Queue<Object> getRpn(String expression) {
Queue<Object> valueQueue = new LinkedList<>();
Stack<String> optStack = new Stack<>();
String munStr = "";
for(int i=0;i<expression.length();i++) {
char ch = expression.charAt(i);
String str = String.valueOf(ch);
if(ch>='0'&&ch<='9') {
munStr +=str;
}else {
if(!munStr.equals("")) {
valueQueue.add(Integer.valueOf(munStr));
munStr="";
}
if (ch=='(') {
optStack.push(str);
}else if (ch==')') {
while (optStack.size()!=0&&!optStack.peek().equals("(")) {
valueQueue.add(optStack.pop());
}
optStack.pop();
}else {
while (optStack.size() != 0&&getOptionLevel(optStack.peek())>=getOptionLevel(str)) {
valueQueue.add(optStack.pop());
}
optStack.push(str);
}
}
}
valueQueue.add(Integer.valueOf(munStr));
while (optStack.size()!=0) {
valueQueue.add(optStack.pop());
}
return valueQueue;
}
/***
* 对后缀表达式进行计算
* @param valueQueue
* @return
*/
public static int getRpnValue(Queue<Object> valueQueue) {
Stack<Integer> numStack = new Stack<>();
while(!valueQueue.isEmpty()) {
if(valueQueue.peek() instanceof Integer) {
numStack.push((Integer)valueQueue.poll());
}else {
String operation = (String)valueQueue.poll();
numStack.push(getOptionValue(operation, numStack.pop(), numStack.pop()));
}
}
return numStack.pop();
}
/***
* 得到运算符的优先级
* @param opt
*/
public static int getOptionLevel(String operation) {
int result = 0;
switch (operation){
case "+":
result=1;
break;
case "-":
result=1;
break;
case "*":
result=2;
break;
case "/":
result=2;
break;
}
return result;
}
/***
* 得到二元运算的值
* @param operation
* @param b
* @param a
* @return
*/
public static int getOptionValue(String operation,int b,int a) {
int result = 0;
switch (operation){
case "+":
result=a+b;
break;
case "-":
result=a-b;
break;
case "*":
result=a*b;
break;
case "/":
result=a/b;
break;
}
return result;
}
public static void main(String args[]) {
computation("1+((2+3)*4)-5");
}
}
参考了博客: