-
中缀表达式就是平常的式子如: (3+4)×5-6,转化为逆波兰表达式(后缀表达式)为: 3 4 + 5 × 6 -
-
3 4 + 5 × 6 - 计算步骤:
1.从左至右扫描,将 3 和 4 压入堆栈;
2.遇到+运算符,因此弹出 4 和 3(4 为栈顶元素,3 为次顶元素),计算出 3+4 的值,得 7,再将 7 入栈;
3.将 5 入栈;
4.接下来是×运算符,因此弹出 5 和 7,计算出 7×5=35,将 35 入栈;
5.将 6 入栈;
6.最后是-运算符,计算出 35-6 的值,即 29,由此得出最终结果 -
中缀表达式转后缀表达式:如代码所示
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
/**
* @date 2021/06/29
*/
public class ReversePolishMultiCalc {
static final char LEFT = '(';
static final char RIGHT = ')';
static final char ADD = '+';
static final char MINUS= '-';
static final char TIMES = '*';
static final char DIVISION = '/';
public static void main(String[] args) {
ReversePolishMultiCalc rever = new ReversePolishMultiCalc();
String infixExpression = "1+((2+3)*4)-5";
Queue<String> queue = rever.postfixExpression(infixExpression);
int result = rever.calculate(queue);
System.out.println(result);
}
/**
* 中缀表达式转后缀表达式
*
* @param infixExpression
* @return
*/
public Queue<String> postfixExpression(String infixExpression){
/*
1) 初始化两个栈:运算符栈 s1 和储存中间结果的栈 s2;
2) 从左至右扫描中缀表达式;
3) 遇到操作数时,将其压 s2;
4) 遇到运算符时,比较其与 s1 栈顶运算符的优先级:
1.如果 s1 为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
2.否则,若优先级比栈顶运算符的高,也将运算符压入 s1;
3.否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到(4-1)与 s1 中新的栈顶运算符相比较;
5) 遇到括号时:
(1) 如果是左括号“(”,则直接压入 s1
(2) 如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃
6) 重复步骤 2 至 5,直到表达式的最右边
7) 将 s1 中剩余的运算符依次弹出并压入 s2
8) 依次弹出 s2 中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
*/
//储存中间结果的栈s2 ,这里改为队列
Queue<String> result = new LinkedList<>();
// 运算符栈 s1
Stack<Character> charSt = new Stack<>();
char[] chars = infixExpression.toCharArray();
// 数字临时变量
String temp = "";
for(int i = 0 ;i < chars.length;i++){
// 过滤空格
if(chars[i] == ' '){
if(!"".equals(temp)){
result.add(temp);
}
temp = "";
}
else if(chars[i] >= '0' && chars[i] <= '9'){
temp += chars[i];
}
// 处理首位负数
else if(i == 0
&& i + 1 < chars.length
&& chars[i] == MINUS
&& chars[i + 1] >= '0' && chars[i + 1] <= '9'){
temp += chars[i];
}
else if(chars[i] == LEFT){
charSt.add(chars[i]);
}
else {
if(!"".equals(temp)){
result.add(temp);
}
temp = "";
if(chars[i] == RIGHT){
while (!charSt.isEmpty()){
char c = charSt.pop();
if(c == LEFT){
break;
}
result.add(c + "");
}
}
else {
if (charSt.isEmpty() || charSt.peek() == LEFT){
charSt.add(chars[i]);
}
else {
while (!charSt.isEmpty()
&& charSt.peek() != '('
&& Operation.getValue(charSt.peek()) >= Operation.getValue(chars[i])){
result.add(charSt.pop() + "");
}
charSt.add(chars[i]);
}
}
}
}
if(!"".equals(temp)){
result.add(temp);
}
while (!charSt.isEmpty()){
result.add(charSt.pop() + "");
}
return result;
}
/**
* 逆波兰表达式(后缀表达式)计算
* 计算,向下取整,如:10 / 3 = 3
*
* @param postfixExQu 存储后缀表达式所用队列
* @return
*/
public int calculate(Queue<String> postfixExQu){
/*
3 4 + 5 × 6 - :
1.从左至右扫描,将 3 和 4 压入堆栈;
2.遇到+运算符,因此弹出 4 和 3(4 为栈顶元素,3 为次顶元素),计算出 3+4 的值,得 7,再将 7 入栈;
3.将 5 入栈;
4.接下来是×运算符,因此弹出 5 和 7,计算出 7×5=35,将 35 入栈;
5.将 6 入栈;
6.最后是-运算符,计算出 35-6 的值,即 29,由此得出最终结
*/
Stack<Integer> cal = new Stack<>();
try {
while (!postfixExQu.isEmpty()){
String str = postfixExQu.poll();
if(Operation.isOperation(str)){
int b = cal.pop();
int a = cal.pop();
switch (str.charAt(0)) {
case ADD:
cal.push(a + b);
break;
case MINUS:
cal.push(a - b);
break;
case TIMES:
cal.push(a * b);
break;
case DIVISION:
cal.push(a / b);
break;
default:
break;
}
}
else {
cal.push(Integer.parseInt(str));
}
}
} catch (Exception e){
throw new RuntimeException("表达式错误");
}
return cal.isEmpty() ? 0 : cal.pop();
}
}
/**
* 符号操作
*/
class Operation {
/**
* 加減 + - */
static final int LEVEL_01 = 1;
/**
* 乘除 * /
*/
static final int LEVEL_02 = 2;
/**
* 左括号
*/
static final int LEVEL_HIGH = 3;
/**
* 写一个方法,返回对应的优先级数字
*
* @param operation
* @return
*/
public static int getValue(char operation) {
int result = 0;
switch (operation) {
case ReversePolishMultiCalc.ADD:
result = LEVEL_01;
break;
case ReversePolishMultiCalc.MINUS:
result = LEVEL_01;
break;
case ReversePolishMultiCalc.TIMES:
result = LEVEL_02;
break;
case ReversePolishMultiCalc.DIVISION:
result = LEVEL_02;
break;
case ReversePolishMultiCalc.LEFT:
result = LEVEL_HIGH;
break;
default:
System.out.println("不存在该运算符");
break;
}
return result;
}
/**
* 判断是否为一个计算符号
*
* @param str
* @return
*/
public static boolean isOperation(String str){
if(str == null){
return false;
}
char c = str.charAt(0);
return str.length() == 1 && (c == ReversePolishMultiCalc.ADD
|| c == ReversePolishMultiCalc.MINUS
|| c == ReversePolishMultiCalc.TIMES
|| c == ReversePolishMultiCalc.DIVISION);
}
}