逆波兰(后缀)计算器
一、实现原理
二、实现代码(java)
mport java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* 逆波兰(后缀)计算器
*/
public class InversePolishCalculator {
public static void main(String[] args) {
//测试(只需提供中缀表达式)
String expression = "(3+4)*5-20";
//得到中缀表达式的list
List<String> list = infixList(expression);
System.out.println(list);
//得到逆波兰表达式的list
List<String> list2 = suffixExpressionList(list);
System.out.println(list2);
//逆波兰计算
int i = calCalculator(list2);
System.out.println(expression + " = " + i);
}
//方法:为了方便操作,我们提供一个方法将中缀表达式=>中缀表达式的list(即将中缀表达式存如集合)
public static List<String> infixList(String infixExpression) { //传入一个中缀表达式
//定义一个集合,作为中缀表达式的list
List<String> list = new ArrayList<>();
//用于扫描,指向中缀表达式字符位置
int index = 0;
//解决多位数,用于拼接
String str;
//接收遍历的每个字符
char ch;
//遍历中缀表达式,并将其转换为集合
while (index < infixExpression.length()) {
//获取每个字符
ch = infixExpression.charAt(index);
//如果ch是非数字,直接加入集合中
if (ch < 48 || ch > 57) { //数字的ASCII码是在48~57之间
list.add(ch + ""); //转字符串
index++;
} else { //如果出是数字,那么就要考虑多位数
str = "";
//循环每次获得ch,将连续的数字字符拼接成多位数
while (index < infixExpression.length() && (ch=infixExpression.charAt(index)) >= 48 && (ch=infixExpression.charAt(index)) <= 57) {
str += ch; //拼接多位数
index++;
}
list.add(str);
}
}
//返回结果
return list;
}
/**
* 方法:将中缀表达式的list转换为后缀表达式思路:
*/
//为了方便,将中缀表达式的list转换为后缀表达式的list
public static List<String> suffixExpressionList(List<String> list){
//初始化一个栈,用来暂存运算符
Stack<String> s1 = new Stack<>();
//初始化一个集合s2用来存储中间结果,不用栈是因为,中途没有出栈操作,使用集合更方便
List<String> list2 = new ArrayList<>();
//遍历中缀表达式的list
for (String item : list){
//如果item是数(包含多位数),就存入集合list2中
if (item.matches("\\d+")){
list2.add(item);
}else if (item.equals("(")){ //如果item是"(" ,入栈s1
s1.push(item);
}else if (item.equals(")")){ //如果是“)”,操作5.(2)
//在找到“(”之前,将s1中的运算符取出,存入集合list2中
while (!s1.peek().equals("(")){ //s1.peek()方法是查看栈顶元素
list2.add(s1.pop());
}
//去掉“( ”
s1.pop();
}else {
//当item的优先级不大于栈顶运算符的优先级时,操作4.(3),s1栈顶出栈,加入的list2中
//调用自定义的运算符优先级比较类
while (s1.size()!=0 && MyPriority.priority(item) <= MyPriority.priority(s1.peek())){
list2.add(s1.pop());
}
//当s1为空,或item优先级大于栈顶优先级后,item入栈s1
s1.push(item);
}
}
//遍历结束后,将s1栈中的剩下的运算符存入list2集合中
while (s1.size()!=0){
list2.add(s1.pop());
}
//返回结果
return list2;
}
/**
* 计算器
* 思路:
* 例如: (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,由此得出最终结果
*/
public static int calCalculator(List<String> list){
//创建一个栈,用来存储数字
Stack<String> stack = new Stack<>();
//遍历集合
for (String str : list){
//通过正则表达式来获取数字
if (str.matches("\\d+")){ //匹配多位数
//数字就入栈
stack.push(str);
} else { //是符号
//定义一个数,保存计算结果
int res = 0;
//取出栈顶的两个数
int num1 = Integer.parseInt(stack.pop());
int num2 = Integer.parseInt(stack.pop());
if (str.equals("+")){
res = num1 + num2;
}else if (str.equals("-")){
res = num2 - num1; //注意顺序:后出栈的-先出栈的
}else if (str.equals("*")){
res = num1 * num2;
}else if (str.equals("/")){
res = num2 / num1; //注意顺序:后出栈的 / 先出栈的
}else {
throw new RuntimeException("运算符错误");
}
//运算结束后,将运算结果入栈
stack.push(res + ""); //这样写的目的是讲数字res转换为字符串入栈
}
}
//运算结束后,栈中只有一个数,也就是结果
return Integer.parseInt(stack.pop());
}
}
//自定义一个比较运算符优先级的类
//数字越大,优先级越高
class MyPriority{
public static int priority(String operator){
int res = 0;
switch (operator){
case "+":
res = 1;
break;
case "-":
res = 1;
break;
case "*":
res = 2;
break;
case "/":
res = 2;
break;
}
return res;
}