使用栈模拟完整版计算器
说明
- 此计算器可以计算常用的 + - * / ( ) ,但没有考虑小数点
- 若想实现小数的计算,可自行实现
思路分析:
- 将中缀表达式各元素先存储到集合
- 然后将中缀表达式转换为后缀表达式
- 进行后缀表达式的计算
源码及分析
package algorithm.stack_;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
/**
* @author AIMX_INFO
* @version 1.0
*/
@SuppressWarnings("all")
public class CompleteCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true){
System.out.print("请输入你要计算的表达式: ");
String expression = scanner.nextLine();
//去空格
for (int i = 0; i < 10; i++) {
expression = expression.replace(" ", "");
}
expression = expression.replace("=","");
//中缀表达式存入集合
List<String> infixExpressionList = infixExpressionToList(expression);
System.out.println("中缀 : " + infixExpressionList);
//中缀表达式转后缀
List<String> sufixList = infixParseSufixList(infixExpressionList);
System.out.println("后缀 : " + sufixList);
//后缀表达式计算
int res = calculate(sufixList);
System.out.println(expression + " = " + res);
}
}
/**
* 编写后缀表达式的计算方法
*
* @param list 集合中保存要计算的数字和操作符
* @return 计算的结果
*/
public static int calculate(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 = calculateByNumAndOperation(num2, num1, item.charAt(0));
//将计算的结果再入栈
stack.push(res + "");
}
}
//运算结束后留在栈底的就是计算的结果,返回即可
return Integer.parseInt(stack.pop());
}
/**
* 通过数字和操作符计算的方法
*
* @param num1 数字1
* @param num2 数字2
* @param operation 运算符
* @return 计算的结果
*/
public static int calculateByNumAndOperation(int num1, int num2, char operation) {
//定义变量保存运算返回的结果
int res = 0;
switch (operation) {
case '+':
res = num1 + num2;
break;
//减法注意运算顺序
case '-':
res = num2 - num1;
break;
case '*':
res = num1 * num2;
break;
case '/':
//除法也要注意运算顺序
res = num2 / num1;
break;
default:
throw new RuntimeException("运算符有误~~");
}
return res;
}
//编写方法将中缀表达式转换为后缀表达式,方便计算机的计算
//已将中缀表达式个元素存储到集合中,则只需要转换为后缀表达式存储到集合即可
/**
*
* @param ls 中缀表达式所在集合
* @return 返回后缀表达式
*/
public static List<String> infixParseSufixList(List<String> ls){
//定义一个栈用来辅助转换,基于栈的先进后出特性
Stack<String> stack = new Stack<>();
//定义集合保存转换后的后缀表达式
List<String> list = new ArrayList<>();
//遍历中缀表达式的所有元素,按照指定规则将其加入到集合中
for (String item : ls) {
//使用正则判断取出来的元素,如果取出来的是数字,则直接加入到集合
if (item.matches("\\d+")){
list.add(item);
//如果是左括号,则直接入栈
}else if (item.equals("(")){
stack.push(item);
//如果是右括号,则弹出栈中左括号之前的元素,因为考虑到小括号的优先级比其他运算符高
}else if (item.equals(")")){
while (!stack.peek().equals("(")){
list.add(stack.pop());
}
//最后再弹出左括号
stack.pop();
//否则是其他运算符的话就要比较运算符的优先级
}else {
//将高运算符先加入集合,因为要先进行计算
while (stack.size() != 0 && Operation.getOperation(stack.peek()) >= Operation.getOperation(item)){
list.add(stack.pop());
}
//如果是优先级较低的运算符,则直接入栈
stack.push(item);
}
}
//最后将栈中所有的运算符全部出栈加入到集合中
while (!stack.isEmpty()){
list.add(stack.pop());
}
return list;
}
//编写方法将一个中缀表达式存储到集合中
public static List<String> infixExpressionToList(String infixExp) {
//定义ArrayList保存中缀表达式的各元素
ArrayList<String> list = new ArrayList<>();
//定义变量
//定义扫描字符串的指针
int i = 0;
//定义字符串str用来拼接数字
String str = "";
//定义 c 表示当前扫描到的字符
char c;
//循环扫描字符串
do {
//如果当前扫描到的字符是一个非数字,即是一个运算符,则直接添加到List中
if ((c = infixExp.charAt(i)) < 48 || (c = infixExp.charAt(i)) > 57) {
list.add(c + "");
i++;
} else {
//否则扫描到的就是一个数字,需要考虑多位数的情况
//先将str置空
str = "";
//循环判断当前数字的下一位是否任然是数字,如果是,则拼接,否则结束循环
while (i < infixExp.length() && (c = infixExp.charAt(i)) >= 48 && (c = infixExp.charAt(i)) <= 57) {
str += infixExp.charAt(i);
i++;
}
list.add(str);
}
} while (i < infixExp.length());
return list;
}
}
//编写一个类,返回运算符对应的优先级
@SuppressWarnings("all")
class Operation2{
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
//编写方法返回运算符的优先级
public static int getOperation(String operation){
int res = 0;
switch (operation){
case "+":
res = ADD;
break;
case "-":
res = SUB;
break;
case "*":
res = MUL;
break;
case "/":
res = DIV;
break;
default:
//System.out.println("运算符有误...");
break;
}
return res;
}
}