后缀表达式适合计算机进行计算,但是并不适合我们日常计算习惯,特别是碰到表达式特别长的情况下,因此我们使用栈,我们将中缀表达式准成后缀表达式来进行计算。
思路
- 1、初始化两个栈:运算符栈s1和储存中间结果的栈s2;
- 2、从左至右扫描中缀表达式;
- 3、遇到操作数时,将其入栈s2;
- 4、遇到运算符时,比较其与s1栈顶运算符的优先级:
- 4.1、如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
- 4.2 否则,若优先级比栈顶运算符的高,也将运算符压入s1;
- 4.3否则,将s1栈顶的运算符弹出并压入到s2中,再次转到4.1步骤与s1中新的栈顶运算符相比较;
- 5)遇到括号时:
- 5.1 如果是左括号“(”,则直接压入s1.
- 5.2 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
- 6、重复步骤2至5,直到表达式的最右边
- 7、将s1中剩余的运算符依次弹出并压入s2
- 8、依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
举例说明
将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下
因此结果为: 1 23+4 ×+5-
package stack.ReverseCalc;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* 逆波兰表达式(后缀表达式)实现计算器
*
*/
public class ReverseCalcTest {
public static void main(String[] args) {
//中缀表达式转后缀表达式
//1+((2+3)×4)-5 =>转成 1 2 3 + 4 × + 5 -
//字符串转list
String midExpression = "1+((2+3)*4)-5";
List<String> reverseList = getReverseList(midExpression);
System.out.println(reverseList);
List<String> list = parseSuffixExpression(reverseList);
System.out.println(list);
//(3 * 4)* 5 + 6
String express = "3 4 + 5 * 6 -";
//表达式存入list中
//把list 配合stack完成计算
List<String> listString = getListString(express);
int res = cal(listString);
System.out.println("expression res:" + res);
}
public static List<String> getListString(String expression){
//将表达式空格分割
String[] split = expression.split(" ");
List<String> list = new ArrayList<>();
for (String n : split){
list.add(n);
}
return list;
}
public static int cal(List<String> list){
//创建一个栈
Stack<String> stack = new Stack<>();
for (String item : list){
//使用正则表达式取出整数
if (item.matches("\\d+")){
//入栈
stack.push(item);
}else {//运算符
//出栈两个数,计算后,入栈
int num2 = Integer.parseInt(stack.pop()) ;
int num1 = Integer.parseInt(stack.pop()) ;
int res = 0;
if (item.equals("+")){
res = num1 + num2;
}else if (item.equals("-")){
res = num1 - num2;
}else if (item.equals("*")){
res = num1 * num2;
}else if (item.equals("/")){
res = num1 / num2;
}else {
throw new RuntimeException("表达式运算符错误");
}
//结果入栈
stack.push(res + "");
}
}
//最后栈顶的元素就是最终的计算结果
return Integer.parseInt(stack.pop());
}
//中缀表达式转后缀表达式
public static List<String> getReverseList(String expression){
//存放中缀表达式
List<String> list = new ArrayList<>();
//表达式指针
int i = 0;
//拼接多位数
String str;
//遍历字符缓存
char c;
do {
//如果c不为数字,就需要加入到list
if ((c = expression.charAt(i)) < 48 || (c = expression.charAt(i)) > 57){
list.add("" + c);
i++;
}else { // 考虑多位数
str = "";
while (i < expression.length() && (c=expression.charAt(i)) >= 48 && (c = expression.charAt(i))<= 57 ){
str += c; //拼接
i++;
}
list.add(str);
}
}while (i < expression.length());
return list;
}
/**
* 中缀表达式转后缀
* @param list
* @return
*/
public static List<String> parseSuffixExpression(List<String> list){
//符号栈
Stack<String> s1 = new Stack<>();
// 存储中间结果
//Stack<String> s2 = new Stack<>();
List<String> s2 = new ArrayList<>();
//遍历表达式
for (String item : list) {
//若是一个数,加入s2
if (item.matches("\\d+")){
s2.add(item);
}else if (item.equals("(")){
s1.push(item);
}else if (item.equals(")")){
//如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
while (!s1.peek().equals("(")){
s2.add(s1.pop());
}
s1.pop(); // 把左括号( 出栈 清除括号。
}else {
//判断优先级 ,当item的优先级小于等于s1栈顶运算符,
// 将s1栈顶的运算符弹出并压入到s2中,再次转到4.1步骤与s1中新的栈顶运算符相比较;
while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
s2.add(s1.pop());
}
s1.push(item);
}
}
while (s1.size() != 0){
s2.add(s1.pop());
}
return s2;
}
}
class Operation{
//加法
private static int ADD = 1;
//减法
private static int SUB = 1;
//乘法
private static int MUL = 2;
//除法
private static int DIV = 2;
/**
* 返回优先级
* @return
*/
public static int getValue(String operation){
int result = 0;
switch (operation){
case "+":
result = ADD;
break;
case "-":
result = SUB;
break;
case "*":
result = MUL;
break;
case "/":
result = DIV;
break;
default:
System.out.println("该运算符不存在");
break;
}
return result;
}
}
输出结果
感兴趣的同学可以自己将算出来的后缀表达式 结果计算处理。