实现思路
- 将表达式(String类型)存入集合中
- 通过集合来将内容排列成逆波兰表达式的形式
- 在通过逆波兰计算器来进行计算
辅助函数
//用于判断是不是运算符
public static boolean isOper(String str) {//字符串的比较用equals
return "(".equals(str) || ")".equals(str) || "+".equals(str) ||
"-".equals(str)||"*".equals(str) || "/".equals(str);
}
-------------------------------------------------------------------------------
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
//获取运算符优先级
private static int getPriority(String str) {
int result = 0;
switch (str) {
case "+":
result = ADD;
break;
case "-":
result = SUB;
break;
case "*":
result = MUL;
break;
case "/":
result = DIV;
break;
default:
try {
throw new RuntimeException("输入运算符错误");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
return result;
}
-------------------------------------------------------------------------------
//计算方法,传入两个数据和运算符,可以得到相应的结果
static double operation(double num1, double num2, String str) {
double result = 0;
switch (str) {
case "+":
result = num1 + num2;
break;
case "-":
result = num2 - num1;
break;
case "*":
result = num2 * num1;
break;
case "/":
result = num2 / num1;
break;
default:
try {
throw new RuntimeException("运算符输入错误");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
return result;
}
将表达式存入集合
//将expression存到ArrayList中
private static List<String> arraysOrder(String expression) {
String str = ""; //用于组合数字
int index = 0; //用于标记扫描到表达式的哪个位置,也就是指向表达式的指针
String ch = “”; //用于接收扫描到的字符
ArrayList<String> list = new ArrayList(); //创建一个list
do {
ch = expression.substring(index, index + 1); //从表达式中读取一个字符
if (isOper(ch)) { //判断是不是运算符————辅助函数,文章前面有写
list.add(ch); //将运算符加入list
index++; //index后移一位
} else { //如果是数字,就判断下一个是不是数字,如果是就进行组合(循环),然后录入list
do {
ch = expression.substring(index, index + 1); //读取一个字符
str += ch; //进行拼接
index++; //指针后移
//不是最后一个字符,并且下一个还是数字或者小数点,就进行循环
} while ((index < expression.length()) && ((expression.charAt(index) <= 57
&& expression.charAt(index) >= 48) || '.' == expression.
charAt(index)));
list.add(str); //将拼接的字符串录入到list
str = ""; //这里一定要将str置位初值!!!!!!!!
}
} while (index < expression.length()); //限制条件,读到表达式最后一位就停止
return list; //返回list
}
转换成逆波兰顺序
中缀表达式——>逆波兰表达式(后缀表达式)
- 创建一个String栈,用于存储运算符;创建一个list(String),用于存放生成的逆波兰表达式
- 遍历前面得到的 中缀表达式的list 中的所有内容。
- 遇到数字
- 直接录入逆波兰list中
- 遇到括号
- 如果是左括号,就直接压入栈中
- 如果是右括号,就依次弹出栈中的运算符,直至遇到右括号才停止,然后丢弃这一对括号
- 遇到运算符
- 如果是栈中第一个运算符(括号不是运算符),就直接压入栈中
- 如果不是第一个运算符
- 如果运算符的优先级大于栈顶运算符的,直接压入栈中
- 如果运算符的优先级小于或等于栈顶运算符,将栈顶的运算符弹出到list中,然后继续和下一个下一个栈顶运算符比较——所以这里会用到循环
下面给出中缀表达式转后缀表达式的代码
private static List reversalOrder(List<String> tempList) { //传入前面得到的中缀表达式的list
ArrayList list = new ArrayList(); //创建一个list,用来存储中间数据
Stack<String> stack = new Stack<>(); //创建一个栈,用于存储运算符
for (String str : tempList) { //增强for循环,遍历集合中的数据
if (str.matches("\\d+") || str.matches("\\d+\\.\\d+")) { //判断是数,或者是小数
list.add(str); //将数据录入list
-------------------------------------------------------------------------------------
} else { //遇到运算符
if ("(".equals(str)) { //如果是"(",就压入栈中
stack.push(str);
} else if (")".equals(str)) { //如果遇到")",就依次弹出栈中的运算符到list中,遇到"("才停止,然后丢弃这一对括号
while (true) {
if ("(".equals(stack.peek())) { //遇到左括号
break;
}
list.add(stack.pop()); //将中间得到的运算符都录入到list中
}
stack.pop(); //丢弃"("
-------------------------------------------------------------------------------------
} else { //遇到的是运算符
while (true) {
if (stack.isEmpty() || "(".equals(stack.peek())) { //判断栈是不是空,或者栈中是左括号。如果满足一个,就说明是目前栈中的第一个运算符
stack.push(str); //运算符直接入栈
break; //出循环,遍历下一个元素
} else if (getPriority(stack.peek()) < getPriority(str)) {
//如果运算符的优先级比栈顶运算符优先级高,就压入栈——辅助函数,文章前面有提供
stack.push(str); //入栈
break; //出循环,遍历下一个元素
} else {
//和栈顶运算符相比优先级相等或者小于,就将栈顶运算符弹出并录入list中,然后该运算符就和栈中新的栈顶元素相比较(循环)
list.add(stack.pop());
//调用pop之后,下次循环自然就是新的栈顶元素
}
}
}
}
}
//将栈中的所有运算符全部弹出到list中
while (!stack.isEmpty()) {
list.add(stack.pop());
}
return list; //返回后缀表达式
}
逆波兰计算器
思路
- 创建一个栈,用于存储数字(这里是String类型)
- 遍历逆波兰list
- 遇到数字就入栈
- 遇到运算符就从栈中弹出两个数字
- 用后弹出的减去先弹出的(后缀表达式嘛,后面的减去前面的),再将结果压入栈中
public static double calculator(List<String> arr) {
//从左到右,遇到数字就入栈,遇到运算符就弹出两个数据,然后:后弹出的-先弹出的,再将结果入栈
Stack<String> stack = new Stack<String>(); //创建栈,用于存储数字
double num1; //用于接收弹出的数字
double num2; //用于接收弹出的数字
String ret; //用于接收运算符
for (String str : arr) { //遍历list中数据
if (str.matches("\\d+") || str.matches("\\d+\\.\\d+")) { //如果是数字
stack.push(str); //入栈
} else {
//如果是运算符就弹出两个数据,并做运算,然后再压入栈中
num1 = Double.parseDouble(stack.pop());
num2 = Double.parseDouble(stack.pop());
ret = operation(num1, num2, str) + ""; //返回类型为double,将其转化为String类型,因为是<String>栈
stack.push(ret);
}
}
//最后栈中剩一个元素,就是结果
return Double.parseDouble(stack.pop()); //最后一步要记得类型转换
}
举例: